Κυριακή, 29 Ιανουαρίου 2017

An example showing stream operator in M2000

Operator << used here to add to a function a generator, another function to supply a stream of values. Also we see the use of Event object.

Stream operator used for arrays to feed each element, but mainly used for what we see here.

We can make some minor changes and we get a simpler version, without TankControl Group (an object in M2000), and with no Event too. Just delete Line "Group TankControl".., line "Event Probe ..", line "Call Event .Probe...", we have to delete the closing curly bracket (for deleted Group definition) before line "Class SpecificClass...", then line "Event TankControl.Probe....", and we have to change the line "For TankControl" with "For This" (so dot before alfa has a meaning This, or we through For  { } , but keeping inside all the code, because by default a single dot interpreted as This. Keep in mind that a For { } not only tag what is a dot but also make all definitions inside block for temporary use, but here we don't have that issue)

\\ we have a function to simulate a tank quantity change
\\ alfa arguments are:
\\ current tank quantity, optionally quantity (30 by default) to remove if valve is open,
\\ a flag for printing messages (false by default)
\\ and optionally we can pass  as many as we want valve states, true for open, false for closed
\\ we can use the << operator (stream operator) to send valve state
\\ we make a class and a group from that class, named Specific
\\ We can feed Specific with a pattern of valve states (a batch of patterns)
\\ We have 4 options. We can send one pattern as a batch, one time or many (2 options),
\\ or we can send one state at a time for one batch or form many.
\\ We can expand this logic, if we move function's alfa definiton in a group where we put an Event object.
\\ so we can use Event through alfa to stop Specific at some level of tank quantity
LowLevelSet=500
Read ? LowLevelSet \\ read optionally
Group TankControl {
      Event Probe { Read tank_quantity, &exitvalue }
      Function alfa {
            Read tank
            Let quantity=30, messages=false
            Read ? quantity, messages
            exitnow=false
            {
                  Try Stream
                  If empty or tank=0 Then exit
                  Call Event .Probe, tank, &exitnow
                  if exitnow then exit
                  If number Then tank-=quantity : If messages Then Print "Valve open"
                  If tank<0 Then tank=0
                  If messages Then Print format$("Tank quantity={0}", tank)
               
                  Loop
            }
            =tank
      }
}
Class SpecificClass {
Private:
      Dim A()
      myCursor=-1
      many=10
      once, counter, step_cursor
      stepcounter
Public:
      Module SpecificClass {
            .ReSet
      }
      Module ReSet {
            Read ? .many
            Dim .A(.many)=False
            .myCursor<=-1
      }
      Function Feed {
            =True
            .myCursor++
            While .myCursor<.many {
                  If Empty Then Exit
                  Read .A(.myCursor)
                  .myCursor++
               
            }
            If Not Empty Then =False : .myCursor<=.many-1
            .once<=True
      }
      Function ReadAllonce {
            If not .once Then exit
            .once<=False
            If .myCursor>0 Then
            For i=0 to .myCursor { Data .A(i) }
            .counter++
      }
      Function ReadAllmany {
            If .myCursor>0 Then
            For i=0 to .myCursor { Data .A(i) }
            .counter++
      }
      Function ReadOneAtime_once {
            If not .once Then exit
            If .myCursor>0 Then {
                If .step_cursor>.myCursor Then {
                 .once<=False
                 } Else {
                        Data .A(.step_cursor)
                        .stepcounter++
                        .step_cursor++
                 }
            } Else .once<=False
      }
      Function ReadOneAtime_many {
            If .myCursor>0 Then {
                  If .step_cursor>.myCursor Then .ResetStep
                  Data .A(.step_cursor)
                  .stepcounter++
                  .step_cursor++
            }
      }
      Module ResetStep {.step_cursor<=0}
      Module UnlockOnce {.once<=True : .step_cursor<=0}
      Module PrintStepCounter { Print .stepcounter }
}
Specific=SpecificClass()
Function LowLevel {
      \\ need same signature for event
      Read New TankLevel, &exitvalue
      exitvalue=TankLevel<LowLevelSet
}
\\ using Lazy(&LowLevel()) and not LowLevel(), we make the call like the code was in module, so we read LowLevelSet.
\\ and of cource we can tweak the Specific object
Event TankControl.Probe New lazy$(&LowLevel())


Print "Start"
For TankControl {
      If Specific.Feed(True, False, False, True,False,False, True,True) Then {
            Last=.alfa(1000, 35, True)<<Specific.ReadAllonce()
            \\ here we pass manual values
            Last=.alfa(Last, 100, True, True, False, False, True)
            Specific.UnlockOnce
            Last=.alfa(Last, 35, True)<<Specific.ReadAllonce()
            Last=.alfa(Last, 35, True)<<Specific.ReadOneAtime_once()
            Specific.ResetStep
            If Last>0 Then {
                  If Ask("try to empty tank?", "Tank")=1 Then {
                        \\ Last=.alfa(last, 35, True)<<Specific.ReadAllmany()
                        Last=.alfa(last, 35, True)<<Specific.ReadOneAtime_many()
                        Specific.PrintStepCounter
                  }
            }  
      }
}