ThingML
ThingML copied to clipboard
[IDEA] Revise the definition of Ports and the use of provided/required
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?
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
Somehow back to what I proposed in #3, 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