Feedback required: Should parameters be able to change of type?

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 not double, 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 using type=parameter_not_set and a “parameter validation callback”.

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

1 Like

This has finally been implemented, and now by default parameters are statically typed.
The old behavior can also be obtained by setting the “dynamic_typing” field in the parameter descriptor.

The relevant PRs are:

I will be working on documenting some of the decisions that were made and will post a link to that soon.

3 Likes