TelluIoT / ThingML

The ThingML modelling language
https://github.com/TelluIoT/ThingML
Apache License 2.0
101 stars 32 forks source link

[IDEA] Revise the definition of Ports and the use of provided/required #212

Open ffleurey opened 6 years ago

ffleurey commented 6 years ago

There are a couple of issues with the way we currently define ports:

1/ The semantics of provided and required is a bit tricky, it is mainly used for: a) All required ports should be connected for a component to run - but optional port are more explicit to do that. b) It is only possible to connect required ports with provided ports - but actually the messages and in which direction they are sent or received are a better indication for the validity of a connector.

2/ Whenever we define ports we typically also define the "mirror" port which contains the same messages but swapping send and receive.

What if we could define the port once (like we do for messages) and the use it in componenents. The keywords "provided" and "required" can then be used for specifying if the port has to be mirrored or not.

Let me give an example to try to clarify:


thing fragment TimerMsgs {

    message timer_start()
    message timer_cancel()
    message timer_timeout()

    port timer {
        receives timer_start, timer_cancel
        sends timer_timeout
    }   
}

thing MyTimer includes TimerMsgs {

    provides timer

    [...]
    event timer?timer_start()
    [...]

}

thing MyClient includes TimerMsgs {

    requires timer

    [...]
    timer!timer_start()
    [...]

}

// By default, the name of the port is the name of the port in the definition (here timer).
// If we need different names or several instance of the same port we can have

requires timer as timer1, timer as timer2

or

requires timer1:timer, timer2:timer

In this example I have assumed that the definition "port" is done from the point of view of the provider of the service so when a thing "provides" the port it is left as-is but when a thing requires a port, it is "mirrored".

This could help be a bit more compact because I see in my programs that the "double" definition of mirrored ports is a pain when making modifications.

Any opinions? Any good reasons for our current approach which I have missed?

jakhog commented 6 years ago

I like it, it is definitely annoying (and error prone) to make the mirror port every time we use ports. And sometimes I make two fragments with each of those mirror ports (like a _cli and _srv) to keep them close together so that I don't make a mistake. Your proposal would automate that process.

I guess a port also defines a "service", so using your proposal, we would have definitions of services using messages and ports, and then the Things would require or provide a service (which I guess is in line with the original idea of the ports?).

One thing I don't fully understand, is how this changes anything related to your points in 1/? Practically, this proposal would just generate required and provided ports automatically? The semantics and connectors would be exactly the same?

Also, what about internal ports? Would that now be a completely different concept? It wouldn't be too bad if it is, related to #161

brice-morin commented 6 years ago

Somehow back to what I proposed in #3, 6 years ago...

brice-morin commented 6 years ago

But as far as I can see, this seems to be an OK proposition.

Not sure if it is better or not, but for the case we require/provide the same port many times, we might use cardinalities (somewhat arrays of ports), something like:

requires port timer[2]
...
timer!timer_start(...) //no index could be a shortcut for timer[0]
timer[1]!timer_start(...)
...

but I am not sure it is a good idea in practice...

The only good thing is that it allows more easily writting loops, for the cases when we want to send something on all ports of the same type