Σάββατο, 3 Νοεμβρίου 2018

OOP: A group as enumaration variable with events.

Run M2000.exe, write edit a and press enter, copy the code and press Esc, to return to console query input.
Now write a and press enter
This program show how we can make a group to act as an enumeration with two values. Also we place four events.
Events for groups and com objects need underscore to function names, and the code called in same scope where we make the group using withevents clause. ( events for forms and controls on forms use dot and not underscore for any event's function). Because Events functions use the same scope as the parent module, we have to use New to read values to new variables (shadows the same named variables which exist in module), and for variables we can use Local before definition to shadow any same named variable in module
Class is a function which produce a group. Here group is like a value type, we use it without pointer, but name matters for events. So if we place a=HttpStatus we get a copy

At the end we see how we can use pointer to group. There are two kind of pointer, a pointer to a named group, and a pointer to a copy of group (a float group, a nameless). Also we can hold nameless groups in arrays, and also we can make them pointers also. Variable b is a pointer to group and can change value to point to another group.



Class HttpStatus {
Events "trace", "err","high","low"
Private:
      myvalue
Public:
      Enum Status { NotFound=404, MethodNotAllowed=405}
      Set {
            read x ' number or enum
            \\ if number not exist in enum list Then we get an error
            Call event "trace", x
            Try ok {
                  .myvalue<=x
            }
            if not ok Then call event "err", format$("value {0} not accepted", x)
      }
      Value {
            =.myvalue
      }
      Operator "++" {
            old=.myvalue
            .myvalue++
            if old=.myvalue Then call event "high"
      }
      Operator "--" {
            old=.myvalue
            .myvalue--
            if old=.myvalue Then call event "low"
      }
      class:
      Module HttpStatus {
      .myvalue<=.NotFound
      }
}
Group WithEvents HttpStatus=HttpStatus()
Function HttpStatus_trace(New a){
      Print ">>>",a
}
Function HttpStatus_err(New a$) {
      Print a$
}
accHigh=0
Function HttpStatus_high {
      Print "high limit"
      accHigh++
}
Function HttpStatus_low {
      Print "low limit"
}
Print HttpStatus.NotFound, HttpStatus.MethodNotAllowed
Print HttpStatus=404
HttpStatus=HttpStatus.MethodNotAllowed
Print HttpStatus=405
HttpStatus=10
Print HttpStatus=405
\\ 404 is ok
HttpStatus=404
Print HttpStatus
HttpStatus--
HttpStatus++
Print HttpStatus=405
HttpStatus++
Print accHigh=1
Print Type$(HttpStatus)="Group"
Def InferType$(x)=Type$(x)
Print InferType$(HttpStatus)="Status"
\\ for enum types Status letter Case have to match the Case in definition
Module Checkit(a as Status) {
      Print type$(a) ' it is a enum type, not a group, so no events happen
      Print a
      a--
      Print a, eval$(a)="NotFound"
     
}
Checkit HttpStatus.NotFound ' 404 404
Checkit HttpStatus ' 405 404
Print Eval$(HttpStatus)="MethodNotAllowed"
Try ok {
      Checkit 405
}
If error or not ok Then Print Error$ ' Wrong type in module A.CHECKIT
Module CheckThis(a as group) {
      Print "ok", a=405
      a++ ' raise high event, add one to acchigh
}
Try ok {
      CheckThis HttpStatus
}
If Error or not ok Then Print Error$ ' Wrong type in module A.CHECKTHIS
\\ we can pass group not value of HttpStatus
CheckThis Group(HttpStatus)
Print acchigh=2
Select Case HttpStatus
Case HttpStatus.NotFound
      Print "Not Found"
Case HttpStatus.MethodNotAllowed
      Print "Method Not Allowed"
End Select
HttpStatus=HttpStatus.NotFound
Module CheckThisToo(&a as group) {
      Print "ok", a=404
      a++ ' raise high event, add one to acchigh
}
\\ pass by reference
CheckThisToo &HttpStatus
Print HttpStatus=HttpStatus.MethodNotAllowed
\\ check a copy of HttpStatus to a
a=HttpStatus
a++
a++ ' we have no events now, a has a new cleared event list
Print a =405
\\ check a pointer to HttpStatus
b->HttpStatus
Print Eval(b), b=>NotFound, Eval$(b=>NotFound)="NotFound"
b++ ' we get event because b is a pointer to HttpStatus
Try {
      \\ b is an object so we get wrongtype
      Checkit b
}
\\ now we can get the value from b
Checkit eval(b)
\\ no used & because  b is actual a reference to HttpStatus
\\ if we use & then we pass the reference of pointer, not the the reference of Httpstatus
CheckThis b
Dim a(2)
\\ this is the second type of pointer, a pointer to a copy of HttpStatus
a(1)->(Group(HttpStatus))
b->a(1)
Print Eval(a(1))=405
a(1)--
Print Eval(a(1))=404
a(1)=405
Print Type$(a(1))="Group", InferType$(Eval(a(1)))="Status"
a(1)++ ' we get high limit, because a(1) has a float group (nameless), and event list inside is the original one.
b++ ' now we get high limit because b and a(1) show the same nameless (or float) group