Description
"Future" is commonly used synchronization primitive used in many languages and environments.
It allows several "receivers" to wait "computaion" of a single value, and single "receiver" to wait for several values to be computed using same convenient construction.
Although Golang already has channels, it is more like "stream/queue of values" instead of "single value to be computed". To make several "receivers" to wait on single value, one ought to use relatively complex wrappers around channel (usually, waiting for channel to be closed). And usually it lacks of type information of value cause uses interface{}
for value.
Proposal
Add future primitive derived and equal rights to channels. Obviously, it will share representation and a lot of code with channels.
- it is created with
make
sentence:
f := make(future string)
- it could be then split to
receive
andsend
subtypes:
var rf <-future string = f
var sf future<- string = f
- future has same internal representation to buffered channel with capacity == 1, and uses similar receive and send operations.
f <- "hello"
s := <- f
-
there is no "close" of future.
-
'receive" operation is almost equal to receiving from channel with excepts:
- receiver doesn't pop value from a buffer, every receiver receives same values sent to a future
s1 := <- f // it is possible to fetch same value several values s2 := <- f if (s1 != s2 || &s1[0] != &s2[0]) { panic("not the same") }
- there is no "receive with check" operation (cause "future" could not be closed):
s, ok := <- f // this is syntax error
-
"send" has properties of both sending to channel and closing channel:
- like
send to channel
it fills value, stored in a future's buffer, - like
close of channel
it awakes all receivers blocked on a future, - also, like
close of channel
secondsend to future
leads to panic, - to conditionally send value to a future, non-blocking send should be used (using
select
withdefault
)
select { case f <- "world": // do something, if we are first who sent value to a future default: // do something, if someone already filled future }
- to avoid semantic complexity, this is only allowed use of send to future inside of select. It is better to force it on a syntax level.
- as alternative, "send with check" could be introduced, (then "send to future" is completely forbidden inside of
select
) (it could be useful for sending to closed channels too, but it looks like it were rejected in the past).:
if ok := f <- "world"; !ok { // do something, if someone already filled future }
- like
Note: some names construction similar to future as 'I-var' - "immutable variable". Looks like, it will introduce less name collisions with existing code, so type could be named as ivar
:
f := make(ivar string)
var rf <-ivar string = f
var sf ivar<- string = f