Skip to content

Proposal: add "future" internal type (similar to channel) #17466

Closed
@funny-falcon

Description

@funny-falcon

"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 and send 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 second send to future leads to panic,
    • to conditionally send value to a future, non-blocking send should be used (using select with default)
      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
      }

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions