The core concept of ThingML is "thing". A thing defines a component which can send and receive a set of messages asynchronously. Messages are sent and received via ports. The overall behavior of a "thing" is defined using a state machine.
Here is the syntax for the definition of a thing:
// definition of an empty thing thing myThing { /* Some properties */ /* Some messages */ /* Some ports */ /* Some state machines */ }
Properties are global variables defined in the scope of a thing. A Property is typed by a datatype, for example:
// definition of a property of type Integer property myProperty : Integer // definition of a property of type String, with initial value property myStringProperty : String = "init" // definition of a property of type DigitalState property state: DigitalState
Properties can also be used to define constant. In that case we should prefix they declaration by readonly:
// definition of a property of type Integer readonly property myProperty : Integer = 16
These constant properties cannot be modified in a ThingML program. However, note that constants can be refined once, when instantiating a thing in a configuration. Each instance of a thing can thus be affected a different value for this constant.
Note that local variables can be defined in states, exactly in the same way. For local variables defined in the scope of block of code (inside the actions of a state or a transition or in a function) they are declared in a similar way, by replacing the keyword 'property' by 'var'
ThingML state machines communicate by exchanging messages in an asynchronous way. The declaration of a message in ThingML is quite similar, from a syntactical point of view, to the declaration of methods in a Java interface
//defintion of a message with two parameters message sendState(name : String, state : DigitalState );
Ports allows grouping messages into coherent units. Basically, a thing providing a service will declare something like
thing MyThingProvidingServiceA { //request to get the status of the sensor called name message getState(name : String) //response message sendState(name : String, state : DigitalState ); provided port ServiceA { receives getState sends sendState } }
Note that usually, messages are defined in a thing fragment, that can be included in the different things using these messages. See the section about includes and fragments on this page, which provides a refactoring of this example.
Even though ThingML is not an OO language, and thus does not provide plain inheritance, it provides some basic mechanisms to improve the modularity/reusability of fragments of ThingML provides.
A thing fragment can been seen as an interface or abstract class. Typically it declares some messages, but could also define any feature we can find in plan things.
The example defined in the Port section, would then be rafactored into:
//Interface for the service A thing fragment ServiceAMsgs { //request to get the status of the sensor called name message getState(name : String) //response message sendState(name : String, state : DigitalState ); } //Concrete thing providing A thing MyThingProvidingServiceA includes ServiceAMsgs{ provided port ServiceA { receives getState sends sendState } } //Concrete thing using A thing MyThingRequiringServiceA includes ServiceAMsgs{ //This is basically the mirror of the port in the previous thing required port ServiceA { sends getState receives sendState } }
The "includes" keyword is basically related to extends/implements/inherits in OO language. However, the semantic of this include is very simple: it basically means that what is defined in the fragment is "copy-pasted" into the thing including this fragment. No more, no less. No "super", "override" or the like.