Πέμπτη, 7 Ιουνίου 2018

Revision 9 (Version 9.3) plus an example of OOP

In revsion 9, mostly work done for editor. There is a plan for next revision to include the new glist user control from TexViewer, for handling input for Chinese ideograms.



About this example.
This is the OOP program. M2000 is not full OOP, because we can make programs with no use of objects.  A group is the object in M2000. A group may have members, any kind of memory containers, like a variable or an array, and methods as Modules and Functions. Also a Group may have other groups inside, and properties as groups which set or get values from them. We can define operators too. The different in M2000 is that all groups, are one kind. We can use pointers to groups, and method dispatch" is dynamic always.
We can use encapsulation by using private members. By default a group exist without a pointer, under a name or in a position in an indexed container, like an array, or in a position in a stack, or in under a key in a Inventory container (something like a vector). In version 9, of M2000 we can use pointers, so there is a way to keep a group only by pointer. Any group may have a superclass. But a superclass must be prepared as a superclass, so a group can't act as superclass. So we have one level of hierarchy only. A superclass is linked by pointer, and only a subclass has access to unique or with same name superclass members. There is another way to make an accumulative group, which we say that a base group can merge members from another group(s). There is no copy of group. and assign a group to another group (not pointers) we get is a merge function. Also we can change any module/function/operator later (except we defined them as final). Also there is a way to make temporary modules (not explain here) using a reference to group and adding to that reference members (which original group never get).
A named group can export reference to it, and this reference is not a pointer to it. References can't changed to point something else. Pointers may changed to point to another group or to null. References used to pass a by reference a group. Because in m2000 we can pass by reference functions, and group functions, we can call a method of Group B from Group A, passing a reference to group B or passing a reference of a function of Group B which call B own functions. Also there are special events for groups, so we can set an event to perform a call, which means that actual object never knows what call, but is the work of event setup to perform the link action. Here we see something more simple from that.

I get the idea from a Java book, the complete reference ninth edition Oracle Press. Because in java we need to define types before compiling, we use an interface or a superclass as a pointer to make it work for a number of different objects, using the strong element of polymorphism. Such a thing isn't a problem for M2000 because, we don't have compiler. all code are interpreted and there is no need to check types, if we use a function that doesn't exist we get an error. The good in Java is that we get the error before compiling. So how bad is to know in advance, before running a program that the program is ok, by reading it? In any case there are faults, and that faults maybe a compiler can't find, and we need to test run the program, maybe many times. M2000 can be used for prototyping, means to make programs from ideas, without optimizations by any compiler. We need to get exactly what we want to get, and anything else is a fault.


\\ make console 60 chars by 40 lines
Form  60, 40
Module Global PressSpaceBar {
      Print "Press SpaceBar"
      \\ using Wait we pass control to os
      \\ this happen if we use standard speed (Fast) or slow speed
      \\ based on a timer. but in extreme speed (Set Fast !) this not hold
      \\ we have to use Wait 0 or something
      While Inkey$<>" " {Wait 0}
}
Module Inside {
      \\ this is inside Inside and we have to call it to create and use anything defined here
      \\ A superclass is group with not members immediate exposed
      \\ to ger members we have to copy it to a name
      \\ a copy of a superclass make two things. One is a copy of all members to new name
      \\ and second a pointer to superclass, so we can get superclass same members, or unique members
      \\ through subclass, using For SuperClass Blcok. But here we don't use it
      \\ We only demonstrate  how "virtual function" works
      \\ for this example we can alter SuperClass with Group
      \\ the output will be the same
      SuperClass Figure {
      Private:
            dim1, dim2
      Public:
            Group GetDim1 {
                  Value {
                      link parent dim1 to dim1
                      =dim1
                  }
            }
            Group GetDim2 {
                  Value {
                      link parent dim2 to dim2
                      =dim2
                  }
            }
            \\ a property is a group always public
            \\ and we can make a Value part, a Set part, or each of these parts
            \\ here we place Value without block, and we set first Value to zero
            \\ so this is a read only property
            \\ there is a [AreaProp] private member in Figure which we can alter it
            Property AreaProp {
                  Value
            }=0
            Function Area {
                  Print "Area for Figure is undefinded"
                 =.AreaProp
            }
            \\ each time we place new dim1, dim2 values, we erase AreaProp
            \\ see <= we use to asign value in a member - otherwise we make a local variable.
            \\ <= not used for arrays (they defined using Dim, or Local or Global)
            Module Figure(.dim1, .dim2) { .[AreaProp]<=0 }
      }
      \\ A class is a function which return a group
      \\ also it is ag lobal functions - and exist until this module end
      \\ but his not hold if class defined in a group.
      \\ here constructor (same name as class name), get three things
      \\ a group, a
      Class Rectangle {
      \\ after class:  all modules/functions can be used only inside this "class" function
      \\ so Rectangle used once only
      \\ we can use module Rectangle(sup, a, b) without types
      \\ or Module Rectangle { Read sup, a, b  : ...code here }
      class:
            module Rectangle(sup as group, a as double, b as double) {
                  \\ sup is a group, so we can use figure to construct it
                  \\ figure is not a constructor, because can't change "this" but values of members only
                  sup.figure a, b
                  \\ we can add some properties, or we can change any property/function/module
                  \\ using additional group definition
                  group sup {
                        Property AreaProp {
                               Value {
                                    if Value=0 then {
                                    \\ compute once, and saveit to [AreaProp] in parent private member
                                    \\ a property is a group inside a group, and can't read parent members
                                    \\ we have to link (to make references)
                                           Link parent dim1, dim2, [AreaProp] to dim1, dim2, Ap
                                                Value=dim1*dim2
                                                AP=Value
                                    }
                              }
                        }
                        Function Area {
                              Print "Inside Area For Rectangle"
                            \\  =.dim1*.dim2
                              =.AreaProp
                        }
                  }
                  \\ so now we can place a copy of final sup to This object
                  this=sup
            }
      }
      Class Triangle {
            class:
            module Triangle(sup, a, b) {
                  sup.figure a, b
                  group sup {
                        Property AreaProp {
                               Value {
                                    if Value=0 then {
                                    \\ compute once, and save it to [AreaProp] in parent private member
                                          Link parent dim1, dim2, [AreaProp] to dim1, dim2, Ap
                                          Value=dim1*dim2/2
                                        Ap=Value
                                     }                                         
                              }
                        }
                        Function Area {
                              Print "Inside Area For Triangle"
                              =.AreaProp
                        }
                  }
                  this=sup
            }
      }
      Fig1=Figure
      Fig1.Figure 10, 10
      M=Fig1.Area()
      Print M
      Rect1=Rectangle(Figure, 9,5)
      M=Rect1.Area()
      Print M
      Triag1=Triangle(Figure, 10,8)
      M=Triag1.Area()
      Print M
      \\ NOW WE USE A POINTER TO OBJECT
      GroupRef->Fig1
      M=GroupRef=>Area()
      Print M
      GroupRef->Rect1
      M=GroupRef=>Area()
      Print M
      GroupRef->Triag1
      M=GroupRef=>Area()
      Print M
      Dim A(12)
      \\ FIRST WE USE COPIES OF OBJECTS IN ARRAY
      \\ EACH COPY IS A NAMELESS OBJECT. EXIST ONLY AS AN ITEM IN AN ARRAY.
      \\ ALL MEMBERS ARE HIDDEN FROM SYSTEM, WHEN NOT IN USED
      \\ EACH TIME WE USE A NAMELESS OBJECT  IT GET A HIDDEN NAME, AND OPEN FOR USE
      A(0)=Fig1
      A(1)=Triag1
      A(2)=Rect1
      For k=0 to 2 {
            M=A(k).Area()
            Print M
      }
      \\ WE CAN OPEN USING FOR
      For A(1) {
            Print .getdim1, .getdim2
            \\ MM is a temporary group
            \\ and get a copy of A(1) (which is a copy of Triag1)
            MM=This
            Group MM {
                  Module PrintDim1Dim2 {
                        Print "Read from a copy of group"
                        Print .Dim1, .Dim2
                  }
            }
            MM.PrintDim1Dim2
            \\ Because we know that dim1 and dim2 are the two first members
            \\ and the fifth is [AreaProp], we can get  references to them
            \\ and also these are for temporary use, in this block
            \\ Read statement have some variants...
            Read From MM, &d1, &d2,,,&Area
            \\ this is the only way to get a referenve from private members, outside of an object
            Print d1, d2, Area
            d1*=2
            d2*=3
            Area=0 ' erase it, so we can copmute it again
            Print d1, d2, Area
            Print MM.AreaProp
      }
      PressSpaceBar
      \\ we can use nested for, or multiple object in any for
      \\ but there is a rule of dots
      \\ in each execution object each added object in For { } add a dot
      \\ so for A(0) we have one dot, fot A(1) two and for A(3) three
      For A(0) {
      \\ also first object can be This (if code run outside of a group member module or function, or a child module or function everywhere)
            For A(1), A(2) {
                  Print "Figure:", .getdim1, .getdim2
                  Print "Triangle", ..getdim1, ..getdim2 ' look double dot before name
                  Print "Rectangle", ...getdim1, ...getdim2 ' look triple dot before name
            }
      }
      PressSpaceBar
      \\ NOW WE USE POINTERS TO OBJECTS
      A(3)->Fig1
      A(4)->Triag1
      A(5)->Rect1
      For k=3 to 5 {
            M=A(k)=>Area()
            Print M
      }
      PressSpaceBar
      \\ NO WE USE POINTERS TO UNAMED OBJECTS
      A(6)->A(0)
      A(7)->A(1)
      A(8)->A(2)
      For k=6 to 8 {
            M=A(k)=>Area()
            Print M
      }
      PressSpaceBar
      \\ NOW WE USE POINTERS TO POINTERS TO NAMED OBJECTS
      \\ NAME OBJECTS ARE "STATIC" MEANS THAT EXIST UNTIL NAMES GET OUT OF SCOPE
      \\ AND THAT HAPPEN AT THE END OF EXECUTION OF A MODULE (WHICH IS THE END OF AN EXECUTION OBJECT)
      \\ OR IN A FOR OBJECT(S) BLOCK WHICH ALSO DESTROY ANY NEW NAME (BUT EXECUTION OBJECT NOT END)
      A(9)->A(3)
      A(10)->A(4)
      A(11)->A(5)
      \\ THIS IS NOT A FOR OBJECT BLOCK BUT A FOR LOOP BLOCK
      For k=9 to 11 {
            M=A(k)=>Area()
            Print M
      }
      PressSpaceBar
      \\ before exit we push array to stack of values
      Push A()
}
\\ we call inside just  by name or using Call Inside (its not the same, but most of the times behave the same)
Inside
Print "Return from Inside Module"
\\ At this point there is nothing to tell us , or M2000 Interpreter that a superclass exist, and some other objects
\\ But there is an array  (with no name) at the top of stack of values
\\ Now we can define an array just by reading an array from stack of values
Read M()
\\ Lets see what we can do with objects in that array1
Z=M(1).Area()
Print Z
\\ We can use => for nameless objects
Z=M(2)=>Area()
Print Z

Try Ok {
      \\ this block needed to catch the error after
      \\ we get an error because we have "smart pointers" to names, but names aren't here (they erased)
      \\ so pointers
      Z=M(4)=>Area()
      Print Z
}
If Not Ok Then Print Error$
Z=M(7)=>Area()
Print Z
\\ also we can use dot and not => for array items which are pointers to groups or groups
Z=M(8).Area()
Print Z
Try Ok {
      \\ this block needed to catch the error after
      \\ we get an error because we have "smart pointers" to names, but names arren't here (they erased)
      \\ so pointers
      \\ M(9) to M(11) are pointers to same "named groups" as the M(3) to M(5)
      Z=M(10)=>Area()
      Print Z
}
If Not Ok Then Print Error$
\\ so from 12 items, we have 0 to 2, three real nameless groups, each one has a  pointer to same superclass
\\ although we didn't use the superclass to full strength, to supply common members for all subclass
\\ Three pointers to  these three groups in positions 6 to 8. All other positions have "broken" pointers.
\\ we can erase  group item using a zero Long literal
M(3)=0&, 0&, 9&
M(9)=0&, 0&, 0&
Print Type$(M(11))="Long"
\\ we can't use M(1)=>dim1+=100  because dim1 is private
for M(1) {
      .figure .getdim1+100, .getdim2
}
\\ because M(7) is a pointer to same object as M(1) we get  the change in M(7) too
Print M(7)=>getdim1
\\ we can get  a copy of object using Group() function
M(4)=Group(M(7))
\\ we can't use M(7)=>dim1-=100 because dim1 is private
for M(7) {
      .figure .getdim1-100, .getdim2
}
\\ because M(1) is a pointer to same object as M(7) we get  the change in M(1) too
Print M(1)=>getdim1
Z=M(4).Area()
Print Z
\\  now M(10) is a pointer, and M(4) is a pointer too same group, a copy of group which point the M(7) pointer.
M(10)->M(4)
Z=M(10).Area()
Print Z
\\ So in an environment which all objects are interpreted and not "compiled", we can use them without "blue prints", but actual as is.
For i=0 to 2 {
      Print M(i).AreaProp
}
For i=0 to 2 {
      Print M(i).AreaProp
}
For M(4) {
      Z=.Area()
      Print .AreaProp, .GetDim1, .GetDim2
      Print Z
}