Κυριακή, 29 Οκτωβρίου 2017

Superclass in M2000, Some examples (new)

In M2000 a group is the base for OOP.
What is a Group:
  • A not reference type variable
  • An open list of members
  • Some members can be private and some public
  • Member can be any type of variables including groups, modules, functions, and special members
  • Special Member are the Operator, Value, Set, Properties
  • A Value member is a function to return a value
  • A Set member is a function used when we assign an expression to group
  • Value and Set can have parameter list.
  • Operators (like + - * /, <> >= <= =, and ++ --)
  • Properties are groups with Set/Value or Set or Value members, and we can add more if we want. Properties are always Public.
  • If not value supported, a group export a copy of it (a nameless group). 
  • If value supported a named group can return copy using Group(name)
  • When no Set supported Assigning a group B to group A a merge happen, so A has a B inside but maybe has more members.
  • When a Set supported then assigning a group with a value, means calling the Set function to do something for that.
  • Each Group (and inner groups) can have a SuperClass, a pointer to a nameless group for class variables, and for used as a base blue print, in copies. Each group (and each inner group) can have access to superclass variables.
  • A superclass can't have a superclass.
  • Inheritance gained by merging groups of different kinds.
  • There are no interfaces for groups. We have to merge a group with a role of interface.
  • Encapsulation provided by private variables/objects/modules/functions
  • Polymorphism in M2000 is something simple, because there are no interfaces, so by using group merge function, or adding/replacing members, we can make objects with some members with same names but different functionality.
A group may have a name, or not.
  • A group without name has all members (public and private) in private space. To operate a nameless group, interpreter has to give it a name before, and place members to appropriate lists. Nameless groups have only position in a container, and we get access to them by using index or key or position. Assigning a nameless group somewhere in a container interpreter empty first the place and then place the group.
  • A group with name has all members in appropriate lists (the global list for variables/arrays, and the global list for modules/functions). When we pass a group by reference all members passed by reference too, but actual group passed by copy, so in a reference group we can add anything for temporary use. There is a second type of reference by using weak reference which not reproduce all members as references, and each time we use a member the weak reference added to name of member. So with that we get actual group by reference, but no member addition allowed.

We can use weak reference for named groups, and nameless groups in arrays providing array name and index(es).

This is an example using a user function to return a weak reference for inventory. Weak reference is used where we have a generic module, which can work with a reference from a named group, a group in array or a group in inventory. Inventories are reference type, so passing it by value is a copy of pointer. But here we pass the name of inventory including the key.
Function Weak$() work for arrays preparing the index(es) evaluating the expressions before export the string.
In version 9.0 revision 9 repaired code for calling superclass A from a calling in superclass B. We can't have two superclasses references in one group, but because a group may have groups inside, each group may have a reference to superclass. A group is not a reference type in M2000, except for superclass.


Inventory alfa
Group Beta {
      x=10
}
Module Generic (what$) {
      For what$ {
            Print .x
      }
}
Delta
=Beta
Delta.x
+=100
Append alfa, "hello":=Beta, 400:=Delta
\\ a way to get a weak reference from an inventory inlcuding key.
Def WeakInventory$(a$, n$, w$) = left$(a$,len(a$)-len(n$)) + n$ + "(" + Quote$(Trim$(w$)) + ")"
N$
=WeakInventory$(&alfa, "alfa","hello")
Print N$
Print eval(N$.x)
Generic N$

N$=WeakInventory$(&alfa, "alfa",Str$(400))
Print N$
Print eval(N$.x)
Generic N$

Dim a(10)
a(2)=Beta
N$=weak$(a(1+1))
Print N$
Print eval(N$.x)
Generic N$

So now we have an idea about groups, so go on to next example. We make a function Generator to return a lambda function. This lambda function hold A, a SuperClass. This Superclass has a unique member, counter. Has also public members  an id, stuff$. So we make Super as a lambda function (so exist this name Super()). We pass an name to Super and we get a group, with id filled appropriate.


Function Generator {
      SuperClass A {
            Unique:
                  counter
            Public:
                  id=0
                  stuff$=""
            Function Many {
                  For SuperClass {
                        =.counter
                  }                  
            }
      }
      = Lambda A (what$)->{
            tmp=A
            \\ adding a module
            Group tmp {
                  Module Add2counter {
                        For SuperClass {
                              .counter++
                        }
                  }
            }
            tmp.Add2counter
            M=A \\ make a group using SuperClass
            For M {
                  .id=.Many()
                  .stuff$=what$
            }
            =M
      }
}

Super=Generator()
A=Super("Babis")
B=Super("George")
Print A.stuff$, B.stuff$
Print A.many()



In the next example we make something more advanced. We want some more members, and a way to read members from specific functions, Super() and Super$()
Also see how we use optional passing variables in functions.


Function Generator {
      \\ this is a temporary global variable.
      Global typename$="sometype1"
      \\ we can read optional
      Read ? typename$
      \\ a SuperClass is a special Group
      \\ but at creation time, copy definition in a class function
      \\ so to read typename$ must be global
      SuperClass A {
            Unique:
                 counter,
                 magic=random(100000000),
                 type$=typename$
            Public:
            Function Super {
                  For SuperClass {
                              =eval("."+letter$)
                  }                  
            }
            Function Super$ {
                  For SuperClass {
                              =eval$("."+letter$.) ' need a dot after last $, to get a weak reference.
                              \\ try without dot.   =eval$("."+letter$)
                        
                  }                  
            }
      }
      = Lambda A (what$)->{
            M=A
            Group M {
                  id, stuff$
                  Class:
                        \\ if we copy M, then anything as CLASS: can't copied.
                        Module Add2counter {
                              For SuperClass {
                                    .counter++
                              }
                        }
            }
            M.Add2counter
            M.id=M.Super("counter")
            M.stuff$=what$
            =M
      }
}
\\ we can make global the "Super" lambda
\\ Super has a closure, the Superclass.
Global Super=Generator("myType") \\ we can use =Generator() to get default value for typename
A=Super("Babis")
B=Super("George")
Print A.stuff$, B.stuff$
Print "A",A.id, A.Super("magic"), A.Super$("type$")
C=Super("John")
For C {
      Print "C", .id, .Super("magic"), .Super$("type$")
}
Print "Total objects:", A.Super("counter"), B.Super("counter"), C.Super("counter")
Rem 1: List   \\ list variables
Rem 2: Modules ? \\ list modules/functions in memory


More advanced. Now function Generator return Group (not lambda as previous example). Group now has a value member.

  Global typename$ ="hello there"
  Function Generator {
      \\ this is a temporary global variable.
      Global typename$   ' shadow any global typename$
      Set Read typename$ = "sometype1"   ' alter any global or make a new
      \\ a SuperClass is a special Group
      \\ but at creation time, copy definition in a class function
      \\ so to read typename$ must be global
      SuperClass A {
            Unique:
                 counter,
                 magic=random(100000000),
                 type$=typename$
            Public:
            Function Super {
                  For SuperClass {
                              =eval("."+letter$)
                  }                  
            }
            Function Super$ {
                  For SuperClass {
                              =eval$("."+letter$.) ' need a dot after last $, to get a weak reference.
                              \\ try without dot.   =eval$("."+letter$)
                  }                  
            }
      }
      M=A \\ make a M as an A
      \\ so now we extend M
      Group M {
            \\ interpreter intialize members automatic
            id, stuff$
            \\ we set a return Value with a parameter
            Value (what$) {
                  M=This
                  For SuperClass {
                        .counter++
                        M.id<=.counter
                  }
                  M.stuff$<=what$
                  \\ because M has a return value with a parameter
                  \\ we have to use Group() which find from name the object and return it
                  =Group(M)
            }
      }
      \\ see remark before
      =Group(M)
}
\\  Generator return a group only.
Global Super=Generator("myType2") ' check it without parameter
A=Super("Babis")
B=Super("George")

Print A.stuff$, B.stuff$
Print "A",A.id, A.Super("magic"), A.Super$("type$")
C=Super("John")
For C {
      Print "C", .id, .Super("magic"), .Super$("type$")
}
Print "Total objects:", A.Super("counter"), B.Super("counter"), C.Super("counter")
Rem 1: List   \\ list variables
Rem 2: Modules ? \\ list modules/functions in memory
Print typename$="hello there"







This is a more advanced example. Code to increment counter is part of Value member in any Group, so we didn't use an Super as group, as in previous example.




Function Generator {
      \\ In 9.2> version we can Read  as global variable
      \\ which we define as Global (Global A make a new A if an old global A exit)
     '  Global typename$="sometype1"
     \\ We can use Set Read  which make a global and use as before newer versions.
     \\ Set  command send line to  CLI, using current stack.
     \\ in that line we can't use local variables, only global, but we can make new globals
     \\ or alter old globals
      \\ we can read optional using set read ? ...   or just  using = "firstvalue" as this:
      Set Read typename$ ="sometype1"

      \\ a SuperClass is a special Group
      \\ but at creation time, copy definition in a class function
      \\ so to read typename$ must be global
      SuperClass A {
            Unique:
                 counter,
                 magic=random(100000000),
                 type$=typename$
            Public:
            Function Super {
                  For SuperClass {
                              =eval("."+letter$)
                  }                  
            }
            Function Super$ {
                  For SuperClass {
                              =eval$("."+letter$.) ' need a dot after last $, to get a weak reference.
                              \\ try without dot.   =eval$("."+letter$)
                        
                  }                  
            }
      }
      = Lambda A (what$)->{
            M=A
            Group M {
                  id, stuff$
                  Class:
                        \\ if we copy M, then anything as CLASS: can't copied.
                        Module Add2counter {
                              For SuperClass {
                                    .counter++
                              }
                        }
            }
            M.Add2counter
            M.id=M.Super("counter")
            M.stuff$=what$
            =M
      }
}
\\ we can make global the "Super" lambda
\\ Super has a closure, the Superclass.
Global Super=Generator() \\ we can use =Generator() to get default value for typename
A=Super("Babis")
B=Super("George")
Print A.stuff$, B.stuff$
Print "A",A.id, A.Super("magic"), A.Super$("type$")
C=Super("John")
For C {
      Print "C", .id, .Super("magic"), .Super$("type$")
}
Print "Total objects:", A.Super("counter"), B.Super("counter"), C.Super("counter")
Rem 1: List   \\ list variables
Rem 2: Modules ? \\ list modules/functions in memory

So here we see something else. How to use a virtual module (method). There is no virtual keyword for M2000, but see the code below. For remind, any module take parent stack for values. When we call something we pass arguments in stack for values. When we call member printdata we call private member super.printdata (the prefix super is as chosen, can be anything, or then name can be anything). M2000 except for user Events never check signatures for parameters. If there are no appropriate Read commands, then we get error, either if we require something to read, or we provide something in wrong type.
So calling member .printdata we pass a number in stack for values, and that stack passed to .super.printdata. (X) is a sugar code for Read X (a line inserted automatic by interpreter, we can see that when we watch the "colored" code running in form Control, opened using Test command)
Later we simulate a Class function (M2000 has classes as group factories), with a lambda function. We need lambda to make a closure for SuperClass Alfa.
Superclass alfa is a special group. Has no members, and has a pointer to a nameless group, and that is the superclasss pointer which used by "Derived" classes


Superclass alfa {
      name$="unkown"
Private:
      module super.printdata (X){
            Print "name:"; .name$
            Print "code:"; X
      }
Public:
      \\ this is a virtual module.
      module printdata {
            .super.printdata
      }
}
\\ simulate Class function
Global N=Lambda alfa (noemptyname$) -> {
      if noemptyname$="" then error "no name given"
      a=alfa
      a.name$=noemptyname$
      =group(a)
}
Beta =N("Babis")
Beta.printdata 999
Group Beta {
      town$="Preveza"
      module printdata {
            Print "town:";.town$
            .super.printdata
      }
}
Beta.printdata 1000
Delta=N("John")
Delta.printdata 1001


 Another example, with a group with two superclasses, one for top group and one for inner group. So we can change inner group superclass. And thats all for mastering Groups in M2000.

 
\\ double super class

Superclass A {
      unique:
      counter
}
Superclass B1 {
      unique:
      counter
}
Superclass B2 {
      unique:
      counter
}
\\ We can make a group Alfa with a member, another group Beta
\\ Group Beta can't see parent group, but can see own member groups
\\ Group Alfa can see everything in nested groups, in any level,
\\ but can't see inside modules/functions/operator/value/set
Group Alfa {
      Group Beta { }
}
Alfa=A
Alfa.Beta=B1
\\ we make 3 groups for marshaling counters
\\ each group get a superclass
Marshal1=A
Marshal2=B1
Marshal3=B2
\\ Now we want to add functionallity
\\ Inc module to add 1 to counter
\\ a Value function to return counter
\\ Without Value a group return a copy
\\ If a group has a value then we can get copy using Group(nameofgroup)
\\ just delete Group Marshal1 and remove Rem when we make Marshal1 using a class function
Group Marshal1 {
      Module Inc {
            For SuperClass {.counter++}
      }
      Value {
            For SuperClass {=.counter}
      }
}
Class AnyMarshal {
      Module Inc {
            For SuperClass {.counter++}
      }
      Value {
            For SuperClass {=.counter}
      }
}
\\ here we merge groups
Rem : Marshal1=AnyMarshal()
Marshal2=AnyMarshal()
Marshal3=AnyMarshal()

\\ So now we see counters (three zero)
Print Marshal1, Marshal2, Marshal3 \\ 0, 0, 0
\\ Now we prepare Alfa and Alfa.Beta groups
Group Alfa {
      Group Beta {
            Function SuperClass.Counter {
                  For SuperClass {
                        =.counter
                  }           
            }      
      }
      Module PrintData {
            For SuperClass {
                  Print .counter, This.Beta.SuperClass.Counter()
            }
      }
}
\\ some marshaling to counters
Marshal1.inc
Marshal2.inc
Marshal2.inc
Marshal3.inc
\\ lets print results
Print Marshal1, Marshal2, Marshal3 \\ 1   2   1
\\ Calling Alfa.PrintData
Alfa.PrintData  \\ 1   2
\\ Merging a group in a group make a change to superclass pointer inside group
Alfa.Beta=B2 \\ change supeclass
Alfa.PrintData  \\ 1   1
For i=1 to 10 : Marshal3.inc : Next i
Alfa.PrintData  \\ 1   11
Alfa.Beta=B1 \\ change supeclass
Alfa.PrintData  \\ 1   2
Epsilon=Alfa
Print Valid(@alfa as epsilon), Valid(@alfa.beta as epsilon.beta) \\ -1   -1
Epsilon.PrintData \\ 1 2
Alfa.Beta=B2 \\ change supeclass
Alfa.PrintData  \\ 1   11
Epsilon.PrintData \\ 1 2
\\ validation being for top group superclass and all members if are same
\\ but not for inner superclasses. This maybe change in later revisions of language.
Print Valid(@alfa as epsilon), Valid(@alfa.beta as epsilon.beta) \\ -1  0