First, let's talk about SELF.
When you run a function, everything works like a classical Forth word : the code is executed.
When you run a method, this is not the same as a method can be implemented by multiple classes and the correct implementation to be executed must be choosen.
How this is working ? Oforth checks the object on top of the data stack and retrieves its class. Then it chooses the implementation according to this class.
(the one directly implemented into the class or into one of its parents).
This object, on the of stack is called the receiver of the method, the SELF, the one that is receiving the method to run.
But that is not finished. Before calling the code of the method found, the receiver is removed from the top of the stack and stored into a local of the method. This local is always created for all methods and its name is "self".
So,
1) When the method's code is executed, the receiver has been removed from the top of the stack.
2) when you use "self" into a method, this is as if you push on the stack the local named "self" and its value is the method's receiver.
For instance :
- Code: Select all
Object method: mydrop ;
12 mydrop .s
12, the receiver, has been removed from the stack, so an empty method is actually a drop.
- Code: Select all
Object method: mynop
self ;
1.2 mynop .s
1.2, the receiver, has been removed from the stack, then pushed back using "self", so this method does nothing.
- Code: Select all
Object method: mydup
self dup ;
"abcd" mydup .s
As the receiver is stored as a local when a method is executed, @ and := use it to get and store its fields.
Now the class methods : they are methods that apply to the class itself, not to an object of this class.
You can think at class methods as functions dedicated to a particular class.
- Code: Select all
Matrix classMethod: id( n )
| i |
n n self new
n loop: i [ dup put( i, i, 1 ) ]
;
Matrix classMethod: id( n )
| i |
n n Matrix new
n loop: i [ dup put( i, i, 1 ) ]
;
: idMatrix ( n )
| i |
n n Matrix new
n loop: i [ dup put( i, i, 1 ) ]
;
Those three codes do the same thing : create an identity matrix of size n
Into class methods, self is the class itself (here, Matrix).
If you have a pre-existting matrix, a class method won't help you.
What you need is a method of the Matrix class.
For instance, if you want to set the same value x on a matrix diagonal, you can write :
- Code: Select all
Matrix method: setDiag( x -- )
| i |
@n loop: i [ i i x self put ]
;
5 5 Matrix new .s 3 over setDiag .s
When #setDiag is called, the matrix on top of stack is removed and stored into the "self" parameter of the method.
When "self" is called, it pushes this matrix back on the stack (as any other local).
When @n is used, it uses the self local to retrieve the value of field "n" and pushes it on the stack.
Franck