Δευτέρα, 15 Ιανουαρίου 2018

Example of using Class and SuperClass in M2000

From http://nilhcem.com/swift-is-like-kotlin/ I get the idea to make a same example as those for Subclass, in Kotlin and in Swift.

In first example we make two classes (functions which return a Group object). These are globals by default (and local if we define a class in a group/class). The second class make a group using first as the base. We get one group only. No reference exist from first to second. This done by merging using This<=NameShape(name$), in constructor. Also in constructor we replace simpleDescription, using a new Group, with same module name (modules are functions which not used in expressions, and also has the idiom of using parent stack value, and return this at exit, so modules can read not only the arguments we pass but all stack of values, and can pass back results if we want, in any number and kind, it is in caller responsibility to take these from stack of values). A class constructor is a module because when we call the function, first make the group as we define it, and then call constructor (if exist) passing only the stack of values. Functions always called in expressions with a new stack of values, and at return stack is desroyed, and any remain value dropped too. So we can make class without constractor.

This class has no constructor. We can pass values to a and b reading stack of values.
Class Look {
      a=number, b=number
}
N=Look(1,2)
Print N.a, N.b


A module with same name as the class name, inside class definition can be used as constructor, and has an idiom, after exit of module anything we make stays in class function (parent of module).
So in this example every change to This (the group which return from class function) in module Square exist after the exit of module and the expanded group returned from function.


Example 1


Class NameShape {
      name$, numberOfSides
      Module simpleDescription {
            Print format$("A shape with {0} sides.", .numberOfSides)
      }
Class:
      Module NameShape ( .name$) {}
}
Class Square {
      sideLength
      Function area {=.sideLength^2}
Class:
      Module Square (.sideLength, name$) {
           This<=NameShape(name$)
           Group Any {
                  Module simpleDescription {
                        Print format$("A square with sides of length {0}.", .sideLength)
                  }            
           }
           This<=Any
      }
}
testobj=Square(5.2, "square")
Print testobj.area()
testobj.SimpleDescription



The second example use a SuperClass, and we make a Square class which use this superclass. All objects from same superclass (not just same blueprint, but same instance) use Superclass to store/read unique values, or default values. A SuperClass is not a function. Intepreter make a Group with no members and put a reference to a closed group, the actual superclass. Any merging with a superclass put a reference to the actual superclass.
Because groups are not reference types, there is no way to have reference to each other, and superclass can't reference to other superclass (we just change reference if we assign to it another souperclass), like a chain of references. When all groups deleted which hold alive superclass then superclass deleted too. There are no deconstructors in M2000. So if we have to use one we have to explicity use one, a module or function to "prepare" any state change.

Example 2


\\ In M2000 we can't stack SuperClasses. Every group can have one or no supercalss. Inner groups may have different superclass, thus it is possible to have a group with more than one superclass, using as holders, inner groups.

\\ Groups are values, but SuperClass is referenced to group, so we can make a number of groups with same reference to a Superclass.

\\ Also note that a SuperClass defintion is Group Defintion, not a Class definition. So has no constructor.

\\ A Class is a function which return a group, and before returned, call the constructor passing any argument, passing in the call

\\ In M2000 calling a user function can be done with any number and kind of argument, because interpreter didn't check, and put anything to a private stack of values. The callee function can read arguments, to variable or in expressions just popping from stack of values, in any line of code, not only as first line. In this context can be raise error, if we read something not in stack, not same type or in empty stack. We can check before we read, and we can use optinal readings, so an empty stack is "optional". We can call with ? as parameter to say "use default" if we read an optional value

SuperClass NameShape {
unique:
      counter
public:
      name$="point", numberOfSides
      Module IncCounter {
            For SuperClass {
                  .counter++
            }     
      }
      Function Counter {
            For SuperClass {
                  =.counter
            }
      }
      Function DefaultName$ {
            For SuperClass {
                  =.name$
            }
      }
      Function simpleDescription$ {
            \\ get a copy of This, in Me
            Me=This
            Read ? Me ' merge argument if exist
            \\ so without argument we get the intial values
            =format$("A shape with {0} sides.", me.numberOfSides)
      }
}
Class Square {
      sideLength
      Function area {=.sideLength^2}
      Function Super.SimpleDescription$ {
            \\ we can use any name, and any dots, but here we place Super.
            For SuperClass {
                  =.SimpleDescription$(This)
            }
      }
Class:
      \\ (This, .sideLength, .name$) change to Read This, .sideLength, .name$
      \\ This is the current group so reading a defined group is a merging function
      \\ becuase we pass a Superclass, we make this group to get a reference to superclass
      Module Square (This, .sideLength, .name$) {
           .IncCounter
           .numberOfSides<= 4
           Group Any {
                  Function simpleDescription$ {
                        =format$("A square with sides of length {0}.", .sideLength)
                  }            
           }
           This<=Any
      }
}
MyNameShape=Lambda NameShape -> {
      M=NameShape
      M.IncCounter
      Read ? M.name$
      =M
}
\\ we can use a lambda function with a closure as a SuperClass
\\ and also for increment counter
test0=MyNameShape("My Point")
\\ we can use superclass as is
test1=NameShape
\\ but we have to adjust counter
test1.IncCounter
Print test1.SimpleDescription$()
Print test1.SimpleDescription$(?) \\ ? = use optional
Print test1.name$ 'point
testobj=Square(NameShape, 5.2, "square")
Print testobj.SimpleDescription$()
Print "area=";testobj.area()
Print testobj.Super.SimpleDescription$()
Print "NameShape name is ";testobj.name$
Print test1.SimpleDescription$(testobj) \\ now we pass another object to test1.
Print test1.DefaultName$()
Print Valid(@test1 as test0) \\ -1  : has same superclass
Print Valid(@testobj as test0) \\ -1 : has same superclass

Group ChangeDefaultName$ {
      Value {} \\ return "", because group has $ in name
      Set {
             For SuperClass {
                  Read .name$
             }
      }
}
\\ A group with $ in name return a string, and has a second name to access members without $.
\\ We can link a superclass after the Group definition
\\ Because we have a Set function, we use Let, which do this: Push NameShape : Read ChangeDefaultName
\\ reading a Group and merging to Group.
Let ChangeDefaultName=NameShape
ChangeDefaultName$="a new point"
\\ here we use second name without $
\\ Because this is an error for intepreter ChangeDefaultName$.DefaultName$()
Print ChangeDefaultName.DefaultName$()
Print test1.DefaultName$()
\\ $. used for a string before a name as a weak reference
a$="ChangeDefaultName"
Print eval$(a$.SimpleDescription$())
\\ or
a$=Weak$(ChangeDefaultName)
Print eval$(a$.SimpleDescription$())
a$=Weak$(ChangeDefaultName$) ' now a$ has $ inside
a$. = "another point"
Print ChangeDefaultName.DefaultName$() \\ another point
\\ change in any object made from same superclass
Print testobj.DefaultName$() \\ another point
Print test1.DefaultName$() \\ another point
Print test1.Name$ \\ point
Print test1.Counter() \\ 3 objects