1. Creating new type
OOP elements fit Wolfram Language very nicely if you thing about in more general sense as an abstract isolated entities of something which can communicate with each other using messages and have their own internal states.
Properties and methods
Let it be an object with a single field default "State"
CreateType[StateMachine, init, {"State"->1}]
init[o_] := o["UId"] = CreateUUID[];
Here we also assigned a unique text ID to it for the future using constructor function init
. By calling now StateMachine
we create an instance of this type
machine = StateMachine[]
Think about it if it as an Association
.
One can assign any properties, but just be aware that Set
has HoldFirst
attribute and set any properties using With
With[{o = machine},
o["State"] = 33
]
One can also see all properties using a special key
machine["Properties"]
See the full guide from Kirill Belov on Objects core package at Wolfam Community
There is no need in installing Objects paclet. This is already a part of WLJS Notebook Kernel
Time to define sort of methods of created types. It is based solely on TagSet
technique widely used in Wolfram Language
StateMachine /: StateMachineChange[s_StateMachine, state_Integer] := With[{},
s["State"] = state;
s
]
StateMachine /: Delete[s_StateMachine] := With[{},
DeleteObject[s]
]
then to update the state we only need to call this on our object instance
StateMachineChange[machine, 1];
machine["State"]
1
In a case if you want an experience close to traditional OOP, one can utilize contexts
StateMachine /: StateMachine`Change[s_StateMachine, state_Integer] := With[{},
s["State"] = state;
s
]
StateMachine`Change[machine, 1];
machine["State"]
Event system
Subscription / published model is quite often applied to objects in OOP. Moreover this comes handy when we need to perform asynchronous tasks and needles to say it plays a great role in communicating between different objects. Here we will integrate it with Events system we built.
Firstly, since Events uses mostly text-strings as an identifiers for event objects, we rely on "UId"
field generated in a constructor function
StateMachine /: EventFire[s_StateMachine, opts__] := EventFire[s["UId"], opts]
StateMachine /: EventHandler[s_StateMachine, opts__] := EventHandler[s["UId"], opts]
StateMachine /: EventClone[s_StateMachine] := EventClone[s["UId"]]
StateMachine /: EventRemove[s_StateMachine] := EventRemove[s["UId"]]
To notify all subscribers we need to modify our method of settings the state
StateMachine /: StateMachineChange[s_StateMachine, state_Integer] := With[{},
s["State"] = state;
EventFire[s, "State", state]; (* THIS LINE *)
s
]
StateMachine /: Delete[s_StateMachine] := With[{},
EventFire[s, "Destroy", Null];
DeleteObject[s]
]
Let us check how it works!
machine = StateMachine[];
EventHandler[StateMachine, Beep]; (* make sound *)
StateMachineChange[machine, RandomInteger[{1,10}]];
Every time you change the state it will make sound.
See more about event system here
One can also subscribe to a particular pattern or topic
EventHandler[StateMachine, {
"State" -> Function[state, Print[state]]
}];
This is a core mechanism in WLJS notebook interface