Question

I'm a bit of a novice when it comes to Squeak Smalltalk, so I'll probably done something wrong or made an erroneous assumption about how Squeak should work. Still, I'd like to know where I went wrong...

I tried to make class Blower derived from Array. Blower is basically an Array, but with an additional instance variable called index and some methods. I thought the initialize method would be automatically run when I created a new object, and that it would initialize both the array and the index variable, but this doesn't seem to happen. If I run initialize "manually" later though, it works as expected.

Array variableSubclass: #Blower
instanceVariableNames: 'index'
(...)

Blower >> initialize
super initialize.
1 to: self size do: [ :ix | self at: ix put: ix ].
self shuffle.
index := 1.

If I do the following in a workspace: blower := Blower new: 10. blower inspect.

Inspect-window shows (Not what I expected): \#( nil nil nil nil nil nil nil nil nil nil ) index: nil

If I run initialize manually, Inspect-window is correct:

blower initialize.

\#( 6 4 1 10 2 8 3 ... )
index: nil

So why doesn't initialize run when I create the Blower and set it up correctly? Is there anyway to automate this so it happens on creation? Ie. getting initialize to work?

Était-ce utile?

La solution

Look at the method ArrayedCollection class >> new. It overrides new to call new: with 0 as a parameter. This replaces the default implementation of new in Behavior which calls initialize. If you really want to do this, implement new and new: as class methods in your class. In each case, call super then call initialize.

new
   ^super new initialize

new: sizeRequested
   ^(super new: sizeRequested) initialize

Having said all that, it's a really bad idea to subclass from Array. Ask yourself "Is it reasonable for me to use a Blower any place I currently use an Array?". If not, it's not a good subclass. Any time you subclass from a collections class you're almost always doing it wrong. What you want is a class called Blower which is a subclass of Object and contains two instance variables - one for the array and one for the index. Your class will now initialize normally. For any operations you want to send to the array, write a method in the Blower to delegate it to the instance variable.

Autres conseils

What David Buck said is correct, but there is a few more things to add, specific to Squeak:

  1. Some collections invoke #initialize: instead of #initialize at instance creation (see for example HashedCollection)

  2. Some other could send both #initialize then #initialize: (see SharedQueue)

  3. But Array class>>new: has a specific implementation that completely bypasses initialize (for the sake of speed, it is known that there is nothing required for initializing an Array)

As David said, it is generally a bad idea to subclass Array, and looking at Squeak, there are too many counter-examples already.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top