Initialize Class variables in Pharo Smalltalk

Viewed 891

I'm having trouble initializing class variables in Pharo. I started by creating a class with a single class variable:

Object subclass: #ClassVariableTestBehavior
    instanceVariableNames: ''
    classVariableNames: 'test'
    package: 'DummyPackage'

And then on the class side I created an initialize message and set the variable to nil.

ClassVariableTestBehavior class >>> initialize
    test := nil

I saved and then created an instance method:

ClassVariableTestBehavior >>> test
    ^ test

and went back again and changed the class method to be:

ClassVariableTestBehavior class >>> initialize
    test := 34

In the playground I then printed the result of the following:

ClassVariableTestBehavior new test.

Which was nil. Why hasn't the value of the class variable updated to be 34?

2 Answers

The class>>initialize method is used only once, when the code is initially loaded from an external file. It does not get run every time the method is edited. (If you modified a comment would you want the data to get wiped out!?) In fact, the nil value didn't come from your method but was just the initial default value.

A common convention is to add a comment to the initialize method with a line of code that could be executed.

"
ClassVariableTestBehavior initialize.
"

I think you are confused about initialize. Based on your comment you want to create a constant value shared among the instances.

The initialize is usually a method for defining values for instance of an object you are creating. The issue with Smalltalk is that not every Smalltalk implementation runs initialize when creating an instance; so watch out for this one.

If you want to share value among instances you can create a class method like this:

ClassVariableTestBehavior class >> #test

Where:

test
  "Class method returning always the same value"
  ^ 34

When you want to access the value you simply do:

ClassVariableTestBehavior test.

If you want to access it when you have your own instance create it you can do it like this:

| instance |
instance := ClassVariableTestBehavior new.
instance class test. "This accesses the class variable"

Edit - due to excellent comment by Leandro, which I forgot to mention.

You should use capital letter for the class variable! (credit to Leandro)

If you would like to have a value stored in a class variable instead of just constant value in a method as I have shown above. You can do it using class variable.

If you define class variable as Test, then you need to have a getter and setter for it.

You would have:

ClassVariableTestBehavior class >> #test

test
  "returns value of class variable"
  ^ Test

ClassVariableTestBehavior class >> #test:

test: aNumber
  "sets the value of class variable"
  Test := aNumber

You would access the value the same way as above (just before the edit).

Related