Design By Contract

I have often put some thought into providing such an idea over the years, but I’ve never come close to putting in enough effort to actually do it. :slight_smile: I’d love to see such work move forward so I’m happy to see someone putting in the work!

Having said that, I think that it would be a major effort to achieve for ROS 1, but quite doable for ROS 2 because many of the things you want to establish as the “contract” for a data-flow-based software component can be implemented using the DDS QoS policies. It would need some thought put into how and where to specify the contracts and then how to translate that into QoS settings. On from that things get more complicated. DDS provides facilities to be informed when a QoS policy has been violated, but how to respond to that is probably going to be very application specific. (In classical Eiffel-style DbC, the contracts are essentially asserts that raise exceptions when violated at run time.)

This can be done using the DDS DEADLINE QoS policy.

This could be done in the message IDL and an assert in the topic publish API. There has been occasional talk in ROS 2 discussions of adding allowable ranges to the IDL, but I don’t think it’s gone anywhere. However if it is going to be node specific it would probably be better done purely in the topic publish API, with a node declaring when it sets up the publisher what allowable ranges the message can hold. This would be fine for run-time checks, but it would make it a lot harder to check contracts statically than having them in the IDL. I think that the need for a unique message definition for every node would be too prohibitive to put contracts in there, though. Other than perhaps things that everyone agrees are sensible for that particular message.

This can also be done using the DDS DEADLINE QoS policy.

Same comment as for the publishing side above.

DEADLINE QoS policy again.

Now we’re getting close to Eiffel-style DbC. These can be done now by putting asserts in your service callback, but what you really want is a way to notify the caller that there was a problem fulfilling the service call due to a contract violation. This would probably require extending the way services are implemented.

The RPC over DDS specification, which was finally published in April this year and hopefully the OSRF’s DDS vendors will rapidly support, does not provide any QoS policies specific to services (only ways to specify existing QoS policies on a per-interface level). Therefore ROS2 would need to decide how to deal with contract violations themselves.

Same as above.

Again same as above.

So the things that you are requesting are doable in ROS 2 using a combination of the DEADLINE QoS policy and adding some features to the API for specifying pre- and postconditions. I do not think it would be a huge level of work, but there would need to be a focus on how the API will work to make it clear what is happening, and making sure that the performance is both minimal and zero-able (i.e. all checks can be turned off).

Design by contract encompasses more than can be specified using strong types. It includes the behaviour of the function called. Even in a language where functions strictly have no side effect, there are parts of this that cannot be expressed by ensuring the types are correct, unless every function takes and returns types unique to that function that exactly define its input and output spaces. For functions that do have side effects (such as class methods) and situations where the side effects are the whole point (many service calls and many data-flow-based nodes), types will not cover everything you want to check.

I think that this would be a useful feature. Adding units to data is a powerful way to catch a common class of potentially fatal errors, and it can be done in a way that has minimal impact on performance.

1 Like