I dug a little bit into concurrency in functional languages. Apparently, almost everything is here in Fantom to use FP-like concurrency. The only thing missing to achieve this is a method to unwrap nested Futures. That's how it should work:
using concurrent
const class Worker : Actor {
new make(ActorPool pool) : super(pool) {}
override Obj? receive(Obj? o) {
Func#call.callList(o)
}
private static Obj? doubleGet(Future f) {
((Future)f.get).get
}
Future join(Future f) {
sendWhenDone(f,[#doubleGet.func,f].toImmutable)
}
}
The meaning is: Future of Future is still just Future. The bad thing is that second get in doubleGet is blocking (on Actor's thread).
Does anyone has a use-case for that feature or its value is purely scientific?
JohnDGTue 9 Nov 2010
When using Future as a monad, it's quite common to deal with "nested futures", to avoid them "bind" or "flatMap is used.
For example, if you're doing an HTTP get from one resource, which you'll use to do additional HTTP gets, then unless you flatten the result you could end up with a future of future of the result.
Instead of using blocking techniques like the one you propose, I recommend bind/flatMap and map be added to Future.
vkuzkokovTue 9 Nov 2010
What I meant to propose to make this work in a non-blocking way. I'm not sure what flatMap is but bind is definitely preferable.
Semantics of bind in their "sequential form" (or at least how I got them) would be:
Sometimes, instead of returning an object Actor might decide to postpone or to delegate to another actor. And all that transparently for a client (holder of a Future instance).
In Actor it can be done with:
virtual Future receiveOrPostpone(Obj? o) {
Future.make(receive(o)) //will create Future as a simple wrapper
}
So, more sophisticated Actors would be allowed to postpone execution (by returning Future of postponed operation) without blocking thread or to end execution normally (with use of Future.make).
qualidafialWed 10 Nov 2010
Couldn't the Future returned from Actor.sendWhenDone be considered a nested Future? e.g.
The benefit to doing it this way is that your actors don't have to know about each other. actorA has a discrete task, as do actorB and actorC. It's some other class's job to string them together into a pipeline. This is nice because now actors a, b and c can be easily re-used.
Contrast this with "nested" futures, where each actor has to know which actor is next in the pipeline, resulting in a highly coupled design and parts that are difficult to re-use.
vkuzkokovWed 10 Nov 2010
@qualidafial
With sendWhenDone you create a pipeline where steps don't know about each other. With "nested futures" it's the other way around.
The client is not necessarily aware that the pipelineing takes place at all (kind of encapsulation).
We define what's the next step after the previous one is completed (so the pipeline is more flexible).
vkuzkokov Mon 8 Nov 2010
I dug a little bit into concurrency in functional languages. Apparently, almost everything is here in Fantom to use FP-like concurrency. The only thing missing to achieve this is a method to unwrap nested Futures. That's how it should work:
The meaning is:
Future
ofFuture
is still justFuture
. The bad thing is that secondget
indoubleGet
is blocking (on Actor's thread).Does anyone has a use-case for that feature or its value is purely scientific?
JohnDG Tue 9 Nov 2010
When using Future as a monad, it's quite common to deal with "nested futures", to avoid them "bind" or "flatMap is used.
For example, if you're doing an HTTP get from one resource, which you'll use to do additional HTTP gets, then unless you flatten the result you could end up with a future of future of the result.
Instead of using blocking techniques like the one you propose, I recommend bind/flatMap and map be added to Future.
vkuzkokov Tue 9 Nov 2010
What I meant to propose to make this work in a non-blocking way. I'm not sure what
flatMap
is butbind
is definitely preferable.Semantics of
bind
in their "sequential form" (or at least how I got them) would be:Sometimes, instead of returning an object Actor might decide to postpone or to delegate to another actor. And all that transparently for a client (holder of a
Future
instance).In
Actor
it can be done with:So, more sophisticated Actors would be allowed to postpone execution (by returning
Future
of postponed operation) without blocking thread or to end execution normally (with use ofFuture.make
).qualidafial Wed 10 Nov 2010
Couldn't the
Future
returned fromActor.sendWhenDone
be considered a nested Future? e.g.The benefit to doing it this way is that your actors don't have to know about each other.
actorA
has a discrete task, as doactorB
andactorC
. It's some other class's job to string them together into a pipeline. This is nice because now actors a, b and c can be easily re-used.Contrast this with "nested" futures, where each actor has to know which actor is next in the pipeline, resulting in a highly coupled design and parts that are difficult to re-use.
vkuzkokov Wed 10 Nov 2010
@qualidafial
With
sendWhenDone
you create a pipeline where steps don't know about each other. With "nested futures" it's the other way around.