In object-oriented programming class is a set (a transitive closure) of types bound by the relation of inheritance. It is said that all types derived from some base type T and the type T itself form a class T.

The first type T from the class T sometimes is called the root type of the class.

A class of types itself, as a type, has the values and operations of its own.
The operations of are usually called methods of the root type.
Both operations and values are called  polymorphic.

A polymorphic operation (method) selects an implementation depending on the actual specific type of the polymorphic argument.

The action of choice the type-specific implementation of a polymorphic operation is called dispatch. Correspondingly, polymorphic operations are often called dispatching or virtual.
Operations with multiple arguments and/or the results of the class are called multi-methods.
A further generalization of is the operation with arguments and/or results from different classes.

 single-dispatch languages are those that allow only one argument or result to control the dispatch. Usually it is the first parameter, often hidden, so that a prefix notation x.f() is used instead of mathematical f(x).
 multiple-dispatch languages allow many arguments and/or results to control the dispatch.


A polymorphic value has a type tag indicating its specific type from the class and the corresponding specific value of that type.
This type is sometimes called the most specific type of a [polymorphic] value.
The type tag of the value is used in order to resolve the dispatch.
The set of polymorphic values of a class is a transitive closure of the sets of values of all types from that class.

In many  OO languages
the type of the class of T and T itself are considered equivalent.
In some languages they are distinct (like in Ada).
When class T and T are equivalent, there is no way to distinguish
polymorphic and specific values.



Task

Create a basic class with a method, a constructor, an instance variable and how to instantiate it.




 
Class zz {
      module bb {
            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 functionality7
            \\ 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
 
      }
}
Dim A(10)
A(3)=zz()
A(3).bb
 
Report {
	there is no super like java super in M2000 when we use inheritance through classes
	see Superclass (example SUP) which is something differnent
	}
 
 
class Shape {
private:
    super.X, super.Y
    Function super.toString$(a=10) {
        ="Shape(" + str$(.super.X,"") + ", " + str$(.super.Y,"") + ")"
    }
public:
       Module final setPosition (px, py) {
           .super.X <= px
           .super.Y <= py
       }
        Function toString$() {
        =.super.toString$()
    }
}
class MoveShape {
      Module MoveRelative(xr, yr) {
            .super.X+=xr
            .super.Y+=yr
      }
}
class Circle as MoveShape as Shape {
private:
    radius
public:
    Module setRadius (r) {
        .radius <= r
    }
    Function toString$() {
        = .super.toString$() + ": Circle(" + str$(.radius,"") + ")"
    }
}
 
class Rectangle as MoveShape  as Shape {
private:
    height, width
public:
      Module MoveLeftSide (p as *Rectangle) {
      \\ for same type objects private members are like public
           for This, p {
               .super.X<=..super.X+..width
               .super.Y<=..super.Y
           }
      }
    module setDimensions (h,w) {
        .height <= h
        .width <= w
    }
    Function toString$() {
       = .super.toString$() + ": Rectangle(" + str$(.height,"") + " x " + str$(.width,"") + ")"
    }
}
c =Circle()
r = Rectangle()
 
r.setPosition 1, 2
r.setDimensions 50, 50
c.setPosition 3, 4
c.setRadius 10
Print r.tostring$()
Print c.tostring$()
r.MoveRelative 100,100
c.MoveRelative -50,-50
Print r.tostring$()
Print c.tostring$()
 
Report  {
	wokring with pointers like in c++
	pointers in M2000 are objects, so null pointer (pc->0&) isn't a zero, but an empty Group (object)
	}
pc->circle()
pr->rectangle()
pr=>setPosition 1, 2
pr=>setDimensions 50, 50
pc=>setPosition 3, 4
pc=>setRadius 10
Print pr=>tostring$()
Print pc=>tostring$()
\\ we can open up to ten objects (from one to ten dots, normaly one to three)
\\ if we use nestef for object {} also we have up to ten objects in total
\\ every for object {} is an area for temporary definitions, after exit from brackets
\\ any new definition erased.
For pr, pc {
	.MoveRelative 100,100
	..MoveRelative -50,-50
	Print .tostring$()
	Print ..tostring$()
}
pr2->rectangle()
pr2=>SetDimensions 30, 30
pr2=>MoveLeftSide pr
Print pr2=>toString$()
 
 