SoftBank Robotics documentation What's new in NAOqi 2.8?

qiFramework 1.1.0

What has changed

Here is an example of current code that does not work as expected:

qi::Future some_function();
qi::Strand strand;
auto callback = strand.schedulerFor([]{ return some_function(); });
auto result = callback();

Before the change, result has type qi::Future and callback might actually block in some conditions, in particular when passed to qi::Future::then().

After the change, result has type qi::Future> and no automatic unwrapping will be done. The outer future corresponds to the wrapped lambda’s result, the inner one is the one returned by some_function().

Typically, code looking like this is affected:

myFuture.andThen(myStrand.schedulerFor([]{ return async_op(); }));

or in types inheriting from qi::Actor:

myFuture.andThen(stranded([]{ return async_op(); }));

How to migrate

The simplest way to migrate the code is to use qi::Strand::unwrappedSchedulerFor instead of qi::Strand::schedulerFor:

auto callback = strand.unwrappedSchedulerFor([]{ return some_function(); });
auto result = callback();

In which case callback returns a qi::Future as before but the unwrapping happens at the right time as expected. Another way to update the code:

auto callback = strand.schedulerFor([]{ return some_function(); })
auto result = callback().unwrap();

Unfortunately both solutions are not compatible with the user code before the patch.

For qi::Actor, qi::Actor::stranded() can be replaced by qi::Actor::strandedUnwrapped():

auto callback = stranded([]{ return some_function(); });

to this:

auto callback = strandedUnwrapped ([]{ return some_function(); });

or you can manually unwrap the result:

auto callback = stranded([]{ return some_function(); });
qi::Future result = callback().unwrap();

As suggested before, you might want to use the define to check if you have to change anything, for example:

#ifdef QI_DETAIL_FEATURE_STRANDED_UNWRAPPED
  myFuture.andThen(myStrand.unwrappedSchedulerFor([]{ return async_op(); }));
#else
  myFuture.andThen(myStrand.schedulerFor([]{ return async_op(); }));
#endif

About unwrapping futures

We added warnings in cases where an implicit conversion from qi::Future> to qi::Future is done, even implicitly. That cast is very problematic so the warnings will help you know when you have some so that you fix it. Unfortunately you will need to do unwrapping in these cases at the right point in your code which can be a bit tricky at first.

Here is a helpful summary. All these cases are correct usage of unwrapping and will all return a qi::Future. Incorrect cases will trigger warnings or not compile starting with the mentioned fixes.

Assuming:

qi::Future f0;
qi::Strand strand;

/* Function which return number**2 (blocking) */
double square (double number);

/* Fonction which return a future of "number**2" */
qi::Future squareButNotNow(double number);

Case 1:

f0.andThen([] (double foo) {
  return square(foo);
});

Case 2:

f0.andThen([] (double foo) {
  return squareButNotNow(foo);
}).unwrap();

Case 3:

f0.andThen(
  strand.schedulerFor(
    [] (double foo) {
      return square(foo);
    }
).unwrap();

Case 4:

f0.andThen(
  strand.unwrappedSchedulerFor(
    [] (double foo) {
      return squareButNotNow(foo);
    }
).unwrap();
Update Watch Copy