Currently in ROS 2 you’re (by default) able to modify the type of a parameter of a running node by making a simple service call.
If the node using the parameter wasn’t expecting that change, it will crash in the next get_parameter()
call throwing an “invalid parameter type” exception.
The only way to avoid this problem is by:
- Registering a “parameter validation callback”, that makes sure that the parameter type doesn’t change.
- Allowing the parameter type to change, but always catching the “invalid parameter type” exception.
The second workaround seems to require unnecessary boilerplate, and though the first one looks ok I would expect that to be the default behavior.
i.e.: I would expect
node->declare_parameter("my_param", ParameterValue(1.0));
to:
- Throw an exception if the user provided override is not a
double
(e.g.--ros-args -p my_param:=hello_world
). - If the parameter is changed by a service call to the
set_parameter
service and the type is notdouble
, the change is rejected (running node doesn’t crash).
This change would make all parameters “statically typed” by default.
That would break all previous code that was actually taking advantage of parameters being “dynamically typed”, so if a change like this is desired we would still need a mechanism to allow the previous behavior.
There are a few alternatives of how to make this change:
- The parameter descriptor already has a type field, we could only set it when declaring a parameter and use the parameter_node_set variant value to indicate “dynamically typed parameter”.
- caveat: the “type” field is currently being updated each time the parameter is set, so you currently get the “actual type” when requesting the parameter descriptor. In this proposal, in the case of “dynamically typed parameters” you would still get “parameter_not_set” (but you can still get the parameter type if you want, using the other parameter services the node provides).
- alternative: same idea, but using an extra “allowed_type” field so the
type
field behaves as before.
- Add a
allowed_types
field that behaves as a bitmask in the descriptor.- Looks like an overkill, but it would be fine.
In the previous alternative, this would be allowed by usingtype=parameter_not_set
and a “parameter validation callback”.
- Looks like an overkill, but it would be fine.
There’s also a problem when the user doesn’t provide a default parameter value:
ParameterDescriptor descriptor;
descriptor.type = ParameterType::Integer;
node->declare_parameter("my_int", descriptor);
IMO in this case declare_parameter()
must fail if the user didn’t provide a parameter override of the correct type.
i.e.: it’s mandatory to provide --ros-args -p my_int:=<AN_INTEGER>
, not passing that argument or providing a value that isn’t an integer should make declare_parameter()
throw.
But maybe instead of the declaration failing when no user override was provided, the first get_parameter()
call should fail, I’m not sure what is desired in this case.
It would be great to have feedback if you think this change would be useful or you think the current behavior is ok and a change would be too disruptive, and also feedback about how the new behavior should exactly be.
Please prefer providing feedback in Add boolean in ParameterDescriptor to enforce parameters static typing by ivanpauno · Pull Request #115 · ros2/rcl_interfaces · GitHub, and not here.
Thanks!
Ivan