These are chat archives for kirkshoop/kirkshoop.github.io

23rd
Jul 2017
Sean Parent
@sean-parent
Jul 23 2017 07:28

Hopefully this isn't too tedious - if you have a library (even if only partially implemented) I'd like to have a look. It still isn't clear to me how lifetime::stop() works (any sample code/library?) or what is meant by a "scope". What happens when you have multiple subscribers to a single and one calls stop()? (I'm assuming a subscriber is a consumer?)

One of the key value propositions, in my mind, for having futures is they allow simple transformations of code to be more asynchronous. You pointed out that vector isn't "thread safe" - but it is as thread safe as an int. That is part of the beauty of value semantics, because ownership of an object is known, the execution context of it is fixed. However, an object does not (and cannot) determine its execution context. If you have an object which is created as part of a CSP implemented as a serialized queue - the execution context is managed by that serialized queue. If it is created on a thread, the execution context might be managed by that thread. During the lifetime of the object, the object may be moved between execution contexts. So if I have a member function on an object that takes a future (or Single) and I want to attach a continuation, the execution context for the object is only known by the owner of that object (or the owner of the owner of the owner). So by not providing a way to set the default execution context on a future, you must provide a way to pass the execution context everywhere, this is tedious, and error prone, and break the model that there is a simple transformation from a function taking an argument of type T, to one taking an argument of type future<T>.

My experience is that most people assume the execution context will naturally be the same context as the code to which the future is passed, and the problem with an immediate execution model is this will be true, sometimes.

You (and others) have me thinking that there is a Future (or Single) "concept" and future<T> should by the polymorphic type to hold that (the same relationship as Function to std::function<>). I'm still struggling with what are the efficient basis operation of Future, is there a set of related concepts here (like FowaredIterator and RandomAccessIterator), and/or is there really a set of distinct concepts.

The capabilities of a future are a function of the future, the associated task, and the execution context, that complicates extracting the useful models.

Kirk Shoop
@kirkshoop
Jul 23 2017 22:12
rxcpp is a very complete library that implements a superset of Single and its algorithms.
rxcpp single
composite_subscription lifetime
observer single
subscriber single_subscription
observable single_deferred
the rxcpp concepts deal with multiple values distributed in time and allow for empty subscriptions
Kirk Shoop
@kirkshoop
Jul 23 2017 22:22
there is also a prototype of what the next rxcpp might look like given c++14 constructs. this has some experimentation that needs more refinement, but is a lot less code to puruse and is much cleaner due to the auto lambda usage.

You (and others) have me thinking that there is a Future (or Single) "concept" and future<T> should by the polymorphic type to hold that (the same relationship as Function to std::function<>).

Yes, both libraries implement type-forgetting for each concept.

Kirk Shoop
@kirkshoop
Jul 23 2017 22:39

I'm still struggling with what are the efficient basis operation of Future, is there a set of related concepts here (like FowaredIterator and RandomAccessIterator), and/or is there really a set of distinct concepts.

Yes, one possible distinction to make in the type is whether the deferral is HOT or COLD.

  • Hot means that the operation is running already and each consumer is sharing the same operation.
  • Cold means that the operation is started again for each consumer and each consumer has a separate operation

Also, the distinction between 1 (Single) and 0..N (Observer/Legion) values can be separate concepts.

Kirk Shoop
@kirkshoop
Jul 23 2017 22:47

What happens when you have multiple subscribers to a single and one calls stop()? (I'm assuming a subscriber is a consumer?)

Yes, a subscriber is a consumer.

When the deferral implementation is Hot, it is considered a multicast producer and stop() will only disconnect the single that is no longer interested (in reactivex the ref_count() algorithm will cancel the hot producer when the last consumer unsubscribes).

When the deferral implementation is Cold, then there is only one single attached and stop() will cancel the producer.

Kirk Shoop
@kirkshoop
Jul 23 2017 22:53
reactivex does not tie a value to an execution context. values are passed through an expression from one context to another. when the rules are followed, a value is only visible in one context at a time.
Kirk Shoop
@kirkshoop
Jul 23 2017 22:59
I am quite steeped in this mental model. The idea of binding a value to an execution context or having a value determine its own execution context seems unworkable to me. The very purpose of these algorithms is to coordinate and combine values as they are produced from different execution contexts. In this model the execution context is the property of each algorithm processing the values, not a property of the value.

My experience is that most people assume the execution context will naturally be the same context as the code to which the future is passed

I think that the truth - the execution context defaults to the context of the producer - is simple enough that it will eventually cease to be surprising.