## How can I create a 2D array and methods to fetch/store

If you have any questions, remarks, ... if you need help... its here...

### Re: How can I create a 2D array and methods to fetch/store

Matrix classMethod: id( n )
| i m |
n n self new dup ->m
n loop: i [ m put( i, i, 1 ) ]
;

I sort of follow that this is a classMethod as opposed to a method. In it's definition it creates a new class of Matrix that's an identity matrix. The class of objects instantiates as an identity matrix. So a new class of matrix is created but I don't quite follow where SELF point's to. I guess I'm still fuzzy of the idea of SELF.

I'm patterning my algorithm off of id(n ) by putting values diagonally in the rows and columns in an pre-existing matrix. But I'm still unsure at going about it being that this was written for a classMethod and not a method.

Here's what I'm trying to do to a matrix object on the stack. Something like this:

\\ reading 4 right then 8 up. The 1 , 0 pair are the direction of the diagonal into a southeasterly quadrant.

<matrix> 4 8 1 0 diagonal .s

0 0 0 1 0 0 0 0
0 0 0 0 1 0 0 0
0 0 0 0 0 1 0 0
0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0

I want to write this myself (I relish the challenge) but I'm a little unsure how to modify the id( n ) classMethod as a simple method as a starting point.
bobgillies

Posts: 60
Joined: 24 Jan 2017 06:26

### Re: How can I create a 2D array and methods to fetch/store

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
Franck

Posts: 166
Joined: 29 Oct 2014 19:01

### Rectangular and Square subclasses of Matrix

Hello Franck,
I've made a slight change to a couple of methods for Matrix class that can now allow me to create, store and fetch into rectangular matrices.

First, the changes:

Matrix method: at( i j -- x )
i 1- @m * j + @values at ; //* I changed @n to @m from the original Matrix example *//

Matrix method: put( i j x -- )
@values put( i 1- @m * j + , x ) ; //* I changed @n to @m from the original Matrix example *//

Now, an example:

tvar: board
8 8 Matrix new to board

board .

0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0

8 4 Matrix new to board

board .

0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0

4 8 Matrix new to board

board .

0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0

My changes to the #put and #at methods properly store and fetch into the row and column, according to the aspect ratio used (square or rectangle) at the time a new Matrix was created. But now I should put my boundries check somewhere so that an error is caught if the row and column parameters supplied to a Matrix object are outside the object's established maximum rows and columns.

The question I have, for the sake of robust and safe OOP practice, should I make a separate subclass each for a SquareMatrix and for a RectMatrix with their boundries checking methods defined in their respective subclasses or is it best to have all those checks contained within the Matrix parent class?

Bob

P.s. My gut is telling me to make a subclass so that I can inquire into a matrix's subclass (rect or sqaure) as a validating check for operating on the class and not simply whether a parameters are within the matrix boundaries.
If you agree, I should make the parent Matrix class a Virtual Class then?
bobgillies

Posts: 60
Joined: 24 Jan 2017 06:26

### Re: How can I create a 2D array and methods to fetch/store

Hi,

For the changes, you should use the matrix lines to compute the index.
If your number of lines is @m, thats fine.

I suggest you to use lines and cols as Matrix attributes names, so :

Code: Select all
`Object Class new: Matrix( lines, cols, mutable values )Matrix method: at( i j -- x )   i 1- @lines * j + @values at ; //* I changed @n to @m from the original Matrix example *//`

For your second question, that is the most difficult (and most important) question you will have to answer when using OOP. Because, this will define your hearachy.

When you create a child for a class, you implement a "IS A" relation. This should be a rule you must follow in order to have a correct class hierarchy :
- Each attribute should apply to the child
- Each method should apply too.

You could create a Matrix class with RectMatrix and SquareMatrix as subclasses, but what attributes or methods will you create at the RectMatrix level ?

In this case, I think that a SquareMatrix IS A Matrix, so :
1) Have a Matrix with all attributes and methods for matrix, and with check bounds.
2) Create a SquareMatrix as a subclass of Matrix, with everything specific to a square matrix.

Franck
Franck

Posts: 166
Joined: 29 Oct 2014 19:01

### Re: How can I create a 2D array and methods to fetch/store

Hi Franck. I 'm eager to learn the ways of structured OOP methodology and I'm very appreciative of your feedback. I refer back to these posts pretty much on a regular basis to accompany my reading of the manual, with a close study of class hierarchy relationship. A challenge for me to digest at this juncture but I am focused on that perspective of OOP. Thank you.

Regards,
Bob
bobgillies

Posts: 60
Joined: 24 Jan 2017 06:26

Previous