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

Abstract Type Emulation in M2000

M2000 has no interfaces, but we can change definitions in groups for functions and modules, and we can declare them as final, so no more change allowed. So to implement an interface as an abstract type, we have to implement functions and modules with an Error statement (we can use a private module to return that error, and we can change the name of module, to return more info.

One type of inheritance comes from combining groups. Here class BaseState is a function which return a group with private members only, without special constructor. We call function AbstractOne which can take a group, or not (we check input with Match() function). First in AbstractOne a group created and then module with same name called, with one feature that other modules don't have, after return of the call nothing erased. But because this call happen inside function AbstractOne() we get a copy of group, and everything erased. So in first call, a group with a combination of two groups feed k, or to speak the truth, k created as the type of function commands, as a group.
If we call k.GetStrings$(), then This.Err called inside k.GetStrings$(). So we have to implement it, and we can do that using a Group command. As we see each member as module and function, get a Final clause to inform interpreter that these members can't changed anymore.
We have a read only property, Z, made it as a Group in a Group, and when we use K.Z in an expression then Value function called. Because an inner group has no direct view of parent's group members, we have to explicitly link parent member (value type, not module) with an new name (maybe the same name). In fact, Interpreter make a new identifier as a reference. We can do that for private variables too. So K.Z return value of K.Z1 which is private and we can't see from outside. Because we didn't make Set { } function for K.Z, and K.Z has Value {}, we can't change K.Z by assign a value. So K.Z is read only property.




Class BaseState {
Private:
      x as double=1212, z1 as currency=1000, k$="ok"
      Module Err {
                  Module "Class.BaseState"
                  Error "not implement yet"
      }      
}
Class AbstractOne {
Public:
      Group z {
            Value {
                  Link parent z1 to z1
                  =z1
            }
      }
      Function M(k as double) {
            .Err
      }
      Module AddCurrency (k as currency) {
            .Err
      }
      Function GetString$ {
            .Err
      }
Class:
      Module AbstractOne {
                  If Not Match("G") Then Exit
                  Read x
                  \\ combine x with This
                  This=x
      }
}
\\ create new group as K
K=AbstractOne(BaseState())
Try  ok {
      Print K.GetString$()
}
If Not ok Then Print Error$
\\ Now Add final functions/modules
Group k {
      Function Final M(k as double) {
            =.x*k
      }
      Module Final AddCurrency (k as currency) {
            .z1+=k
      }
      Function Final GetString$ {
            =.K$
      }       
}
Print k.M(100), k.GetString$()
K.AddCurrency 50.12
Def ExpType$(x)=Type$(x)
Print k.z=1050.12, ExpType$(k.z), Type$(k.z) ' true, Currency, Group
\\ Now combine AbstractOne without new BaseState
\\ but because all functions are final in k, nothing combined
k=AbstractOne()
Print k.M(100), k.GetString$()
For k {
      \\ we can use For Object {} and a dot before members to get access
      Print .z=1050.12, ExpType$(.z), Type$(.z) ' true, Currency, Group
}