Yes, we should probably make the API assume all interactions are async.

So ask for a snapshot of values, have it call you back.  Either with callbacks or coroutines or futures or...

On Wed, Jul 31, 2019 at 3:43 PM Klaim - Joël Lamotte via SG13 <sg13@lists.isocpp.org> wrote:
Thanks Rene and Tony for your replies.

About hardware requiring polling, I totally see your point (as a
gamedev and having xp implementing higher level APIs over these kinds
of devices).
I am mainly looking for a good general solution to avoid the problems
I referred to.

I'm not sure that using callbacks must necessarily imply push models.
If you think it does, could you clarify why? Maybe the examples I used
were too specific.
For example, assuming a poll-only device, what about these styles of interface:

    // 1 - polling and passing to continuation
    device.read([](device_state new_state){ return process(new_state);
});         // state of the data handled by the device
    device.capture_info([&](device_info info){ ui.present(info); });
// info about the device

    // 2 - separate reading from polling
    device.set_state_update([](device_state new_state){
process(new_state); }); // Not called yet.
    device.read_state(); // Poll and pass the data to the update callback.
    device.on_properties_changed([](device_info info){ present(info);
}); // Not called yet.
    device.read_info(); // Poll and pass the data to the update callback.

I reached that idea mainly because of my experience with trying to
define input interfaces that seemed the most "generic", as in workable
in polling-blocking, polling-non-blocking and push-model.
I had good success with example 2, though I didn't have the occasion
to use it in projects with a lot of users yet.

Maybe the proposed receiver/callback api (through the recent executor
papers) is a better direction then.
What about "always returning senders/awaitable for device data access"?

     // 3-a - polling without blocking and add continuations
    auto processed_state = process(co_await device.read());
    // or 3-b
    submit(device.read(), [&](device_state new_state){ // can you
submit more than once for the same sender?
        processed_state = process(new_state);
    });

     // 4 - polling by blocking
    auto processed_state = process(wait(device.read()));

One of the problems I am trying to avoid is ending up with 2
unsynchronized sources of information that can lead to races when
receiving updated data and trying to poll that data in parallel.
In particular this happen when providing both a way to poll and
callback-on-update for the same data.
Experience in several projects (including frameworks for robotics)
shows that having 2 racing sources tends to lead to a lot of issues
for the user code. In one of the cases I've seen, the best solution
for us was to just allow to remove the polling function and add a rule
that setting a callback for the requested data will call it
imiediately with the current state (which implies either polling or
retaining the last state recieved through a push-model).
Which is why I proposed that model.

I'm starting to think that maybe there is actually 3 kinds of device
interfaces: poll-model, push-model and both...

Related question: would it be reasonable to separate the data in two categories:
 - the properties of the device;
 - the data handled by the device (input, output or both - values);
and then have different guidelines depending on these categories?

Sorry, I'm mainly dumping my thought here for now. Thanks for the feedback.

A. Joël Lamotte

On Wed, 31 Jul 2019 at 20:01, Rene Rivera via SG13
<sg13@lists.isocpp.org> wrote:
>
> On Wed, Jul 31, 2019 at 12:16 PM Tony V E via SG13 <sg13@lists.isocpp.org> wrote:
>>
>>
>> On Wed, Jul 31, 2019 at 9:40 AM Klaim - Joël Lamotte via SG13 <sg13@lists.isocpp.org> wrote:
>>>
>>>
>>> 3. Device information should always be acquired through callbacks and
>>> helpers built around them.
>>>
>>
>> Not always.  For some devices, this would require polling, as the device doesn't have a push model.
>
>
> +1
> That's just about all devices game devs care about.
>
>>
>> Also think of a device connected over a network - do you want a constant data stream, or just get data when needed.
>>
>> I guess pull-model devices could use a callback model where you set up the callbacks and then call device.check_for_changes() or something like that.
>
>
> They could, and in game dev we mostly achieve that through an event system. But really important: If you are going to mandate the push model, please also mandate that it be externally driven. Not having control over that causes all kinds of nightmare concurrency interactions (I'm looking at you UIKit).
>
> --
> -- Rene Rivera
> -- Grafik - Don't Assume Anything
> -- Robot Dreams - http://robot-dreams.net
>
> --
> SG13 mailing list
> SG13@lists.isocpp.org
> http://lists.isocpp.org/mailman/listinfo.cgi/sg13
--
SG13 mailing list
SG13@lists.isocpp.org
http://lists.isocpp.org/mailman/listinfo.cgi/sg13


--
Be seeing you,
Tony