Future class suggestions

Noticed a few possible improvements to the Future class, in case anybody wants to do them before I get to them, here’s the list:

There appers to be some mutation of @state that doesn’t appear to be guarded in a MT friendly way. :|
I almost wish crystal could somehow introduce some threading concepts so that “carefully guarding stuff” were no longer necessary, but following the old Ruby way of threading is a valid model as well.

For delayed Futures, the docs aren’t clear as to what happens if it’s cancelled “while performing its compute task.” What will get return? Will it still run?

And a feature request: new method #get_without_raising_unrescued_exceptions (maybe “#join”?), sometimes I just want to wait for a Future, not carefully know (and accomodate for) if it succeeded vs. not. It would return nil I guess.

Just noting ideas here :)

Cheers!

2 Likes

Future was merged on a haste. I’m pretty sure it will go away or change completely in the future (no pun intended :-P).

2 Likes

The future concept is great, though. It can be a lot easier to understand for some use cases than channels. For example:

def send_requests(uris : Enumerable(URI))
  uris
    .map { |uri| future { HTTP::Client.get(url) } }
    .map(&.value)
end

# vs

def send_requests(uris : Enumerable(URI)
  channel = Channel(HTTP::Client::Response).new(uris.size)

  uris.each do |url|
    spawn do
      channel.send HTTP::Client.get(url)
    end
  end

  uris.map { channel.receive }
end

Another benefit is that, with futures, you can trivially guarantee order while the second one requires extra work to do that.

1 Like

I did find it a little…confusing that future and delay are in the global namespace, since they seem rarely used relative to spawn FWIW… :)

A bit more info: I said that they were merged in a haste. That doesn’t mean they aren’t useful. It just means that they will probably be revisited in the future.

3 Likes

Oh, right, I feel like we’ve had this exact conversation before. :joy:

It might be interesting to combine some of these characteristics into normal Fiber as well.

You know, so you can select on fiber instances (without extra boilerplate), and “get” their return values. Might be nice and slick… :)