VisualWorks Smalltalk - can't access parent's methods - oop

I have a problem with class inheritage - I have two classes defined like this:
Smalltalk defineClass: #Field
superclass: #{Core.Object}
indexedType: #none
private: false
instanceVariableNames: 'name type '
classInstanceVariableNames: ''
imports: ''
category: ''
and
Smalltalk defineClass: #CheckBox
superclass: #{Smalltalk.Field}
indexedType: #none
private: false
instanceVariableNames: 'checked '
classInstanceVariableNames: ''
imports: ''
category: ''
in class 'Field' I have a method setName:
setName: n
name := n.
^n
It works perfectly fine for something like this:
|tmp|
tmp := Field new.
tmp setName: 'fancy name'.
, but when I change 'Field' to 'CheckBox' in the above example I always get "Unhandled Exception: MessageNotUnderstood: #setName: ". Do you guys know how am I supposed to make my subclass inherit a setName: method from it's parent? I'm trying to find an answer everywhere, but no luck so far.
EDIT:
Full error message is:

Somehow your CheckBox class didn't get compiled. Check the spelling. Make sure that there's no existing class called CheckBox. Make sure you can see the CheckBox class in your browser.

Just on a lark - in your workspace window, go to the Variables tab and make sure you don't have a variable called CheckBox. If so, delete it and try again.

Ok here's anwser to my question: I'm stupid. I was messing around with my CheckBox initialize method and accidently deleted ^self line at the end. After putting it back there everything works fine. Thanks for your help, David, and sorry for taking your time.

I cannot see the #initialize method on your Checkbox class,
but it was, for some reason, answering nil.
When you changed the last line, so it would answer self,
you also changed whatever had been causing the method to answer nil.
Removing the line that was answering nil
would also have worked.
You can avoid this problem If you write your #new methods like this -
>>new
^self basicNew
initialize
; yourself
so you'll always get the new instance,
instead of like this --
>>new
^super new initialize
whereby you always get whatever it is that
the #initialize method happens to answer.

Related

Why can't I override the #at:put: method in a class derived from the Dictionary-class?

I try to implement a specific Dictionary class in Smalltalk which needs to override the #at:put: method in Pharo and Squeak. But when I create a class having #at:put: as an instance method and I send that methode, I get the error:
Error: Instances of '#SortedDictionary' class are not indexable
The class definition is as follows:
Dictionary subclass: #SortedDictionary
instanceVariableNames: 'index'
classVariableNames: ''
category: 'MyApplication'
An instance is created by overriding new:
!SortedDictionary class methodsFor: 'creation' stamp: 'nanitous 9/28/2015 19:17'!
new
super new.
^self initialize! !
An instance is initialized with:
initialize
index := Heap new.
^self
And the instance method is defined as:
at: anIndex put: aValue
index add: anIndex.
^self at: anIndex put: aValue! !
And I test with the script in a workspace:
| d |
d := SortedDictionary new.
d at: 1 put: 3.
I tried to make a class not derived from #Dictionary but from #Object and used an instance variable dict containing an instance of #Dictionary, but with the same result.
Why can't I override #at:put: and and how can I override this method?
EDIT
Thanks to #lurker and #aka.nice I should have done the following:
!SortedDictionary class methodsFor: 'creation' stamp: 'nanitous 9/28/2015 19:17'!
new
^super new initialize! !
Doing this wrong was outright silly! In the original and wrong code I was trying to index a nil object.
And:
!SortedDictionary instance methodsFor: 'accessing' stamp: 'nanitous 9/28/2015 19:17'!
at: anIndex put: aValue
index add: anIndex.
^super at: anIndex put: aValue! !
Well, I never came to solve this one before solving the #new issue.
Thanks again to everyone taking the trouble to help out here!
Generally, an instance of collection (more precisely a subclass of Collection) is created with #new:, not #new.
The parameter passed to new: is a size, either the size for a fixed size collection (like Array new: 3), or some pre-allocated size for variable size collection (like OrderedCollection, Set, Dictionary, ...).
From the stamp, I guess you are on a Squeak or Pharo flavour, so I will continue explanation with these dialects, it may slightly vary for other flavours.
In Squeak/Pharo, see the definition of HashedCollection class>>new:
new: nElements
"Create a Set large enough to hold nElements without growing"
^ self basicNew initialize: (self sizeFor: nElements)
It sends initialize: not initialize.
So the first thing you have to do is to define initialize: at instance side of your class, and the second thing is to remove definition of new/new: overriding these is rarely ever needed in Squeak/Pharo.
Currently you have a problem in your #new definition, when you tell self initialize what is self exactly? it is the class SortedDictionary, so you initialize the class, not the instance! And you answer the class, not the newly created instance, so you later send at:put: to the class...
It should have been something like newInstance := super new. ^newInstance initialize.
Last, your at:put: definition will loop forever, it should invoke super at: ... put: ...
A couple of nits to pick.
When you write Smalltalk code as text, such as we're doing here,
you can use the format
{classname|blank} {class|blank} >> methodHead
where the first field names the class, the second field tells whether it is class side or instance side, and the '>>' indicates start of source code.
If you don't name the class, we assume the same class as the last one named.
If you don't say it is class side, we assume it is instance side.
So your methods would be written as
SortedDictionary class>>new
^super new
initialize
>>initialize
index := Heap new
>>at: anIndex put: aValue
index add: anIndex.
^super at: anIndex put: aValue
Second, since you're defining a subclass, you only need to define
your own #new (and/or #new:) method if you must override the one that is otherwise inherited from the superclasses. (But you knew that).
Third, whenever you write an #initialize method, you want to get in the habit of writing 'super initialize.' as the first line thereof.
And once you get into said habit, you'll want to get out of the habit of writing your #new methods starting with '^super new initialize', and get into the habit of starting them with 'self basicNew initialize' instead.
I know, everyone learns to do it that other way. (Sigh.)
But that is soooooo wrong.
Extra points if you can figure out why this is so. ;-)

How to initialise a class variable?

I know that for an instance variable all I have to do is put it inside the initialise method in the instance side and assign it a default value. But how I do this for class variable ? I tried to create an initialise method at class side but it did not give my variable a default value so I had to do this in one of my methods
pythonString ifNil:[pythonString := '']
But I don't like this approach.
I also found this for squeak , http://forum.world.st/Howto-initialize-class-variables-td1667813.html again I don't like this approach either. Is there a proper way of doing this. In Python it was fairly simple case of assignment why is it so cryptic for Pharo ?
First of all I hope that you are talking about instance variable of a class object (not a thing that you define on instance side as "class variable").
initialize is working, but it's being run upon instance creation. And instance (a class object) exists already when you define initialize method.
So when you define your class for the first time, you should run it by yourself e.g. YourClass initialize, bun later each time you load your class into system it should be initialised.

Pharo big error?

i have a class at smalltalk in pharo.
i create an instance in global dictionary which is smalltak,
Smalltalk at:#asd put: myobject new.
then i write this code to workspace, mistakely.
Smalltalk at:asd put: myobject new.
and this gives to me error, continuously,
when a press a key from keyboard, i get error my object does not understand, is this byteArray, like that.
how can i solve this issue?
or how can i reset global dictionary?
Ok, this is a fun question.
First of all I suggest you not to do things like that, because globals are usually used for storing classes in them.
Now the cause of the problem is that you don't have to declare vars in workspace, it will create a new war for every name you use. By default new var is nil, so what you've done was putting a nil key in the dictionary
To remove it execute this thing:
Smalltalk globals removeKey: nil ifAbsent: [ ]
Now, if you want to have a unique instance of you class, I'd suggest you using a singleton pattern. This implies defining class instance variable (e.g. default) and a class method:
default
^ default ifNil: [default := self new ].
This will create new instance first time you run it, and then keep it and return it whenever you want it later.

Visualworks Cincom Smalltalk Class Variable Destruction

How can we initialize a class variable in Visualworks Smalltalk and destroy it after its use?
I want to know about ClassVariables. NOT ClassInstanceVariables.
I am implementing Singleton pattern and here is my code
MyClass class>> aClasMethod
aClassVariable isNil ifTrue:[
aClassVariable := 'I am a variable'.
]
^aClassVariable.
Once the variable is created, I am not able to destroy it.
i.e Next time I run my code, I see that the class variable is retaining its previous value.
How can I avoid this?
I tried this:
MyClass allInstances do: [:inst |
inst become: nil
].
But of no use.
The best way is simply to add a class method to set the class variable to nil and then call it whenever it's an appropriate time to clear it. I do this all the time with the Singleton pattern.
i think we usually use singleton pattern so that we only have one object. I don't know why do you want to store a string value in the class variable. Try to store a object so you will have only one copy of that specific object and store values in the instance variables. so that specific object has only some specific values. Then in future if u need to update the values stored in instance variable then make one more method updateValues and do everything in that.

Calling parent class within class method gives me "matching method signature" warning

I have a class that has two classes A and B added to it. In a method in class A, I am trying to call a class B method
Let's assume that the parent class is debugZoneScene, debugZoneLayer is class A and tetraCounter is class B.
Here is a method from debugZoneLayer (class A):
-(void) getHeroVel {
DebugZoneScene *debugZoneScene = (DebugZoneScene*)self.parent;
[debugZoneScene.tetraCounter setTetras];
}
It calls the method, but I get the warning:
'-[DebugZoneLayer getHeroVel]':
'CCNode' may not respond to '-setTetras' (Messages without a matching method signature will be assumed to return 'id' and accept '...' as arguments.)
I've tried Googling this, but I couldn't really find anything that related exactly to my problem. I am using Cocos2D, but I think this problem doesn't have anything to do directly with that, and can still be resolved having knowledge in Objective C. Any ideas?
The compiler is telling you that it thinks that debugZoneScene.tetraCounter is an object of type CCNode, not whatever your ClassB is. Check how tetraCounter is declared and allocated in DebugZoneScene.
You can make the warning go away by casting:
[(ClassB *)(debugZoneScene.tetraCounter) setTetras];
this tells the compiler that you don't care what it thinks and you're sure that the object is ClassB. This doesn't solve the actual problem, however.
Your pseudo really fits you... without more details about the signature of setTetras, it will be quite difficult to guess what is wrong in your code ^^
Anyway did you #import the header for TatraCounter class declaration, so that the file where you wrote this code knows about the methods available (and their signature) for the TetraCounter objects?