Narnach's blog

The thoughts of Wes Oldenbeuving

Result of ACK: Future

| Comments

Wikipedia’s definition of a Future in programming:

In computer science, futures and promises are closely related constructs used for synchronization in some concurrent programming languages. They both refer to an object that acts as a proxy for a result that is initially not known, usually because the computation of its value has not yet completed.

Yesterday evening a number of Rubyists from Amsterdam came together in the public library with our laptops to do cool computer stuff until the library closed.

Among the topics we discussed were new-ish programming languages such Ioke and Clojure. From here the discussion went to the languages that preceded them, like Self and IO.

I think that at some point someone asked “What can IO do that Ruby can’t do?”, so we started looking at the list of features of IO. There we discovered futures.

Futures look nifty: create an object that does not yet have a value and then move on and eventually do something with the object when you need its value. It will block if there is no value yet, which makes sense, but as long as you don’t need the value, you can just move on with your business. This can be useful to do heavy computations or to initiate asynchronous interaction with a remote API. As long as you don’t need the result immediately, a future can be useful.

Then I mentioned Ruby’s Thread#value, which was new to people. So a bit of code was created that looked similar to:

# sleeps for 3 seconds, then prints 615
t = Thread.new { sleep 3; 123}
puts t.value * 5

Explicitly creating a Thread and calling its value does the trick, but it is not very elegant. If you read it, you will probably end think, “What is that Thread doing? Oh, there’s a #value call there. Thread + #value is a future!”. Or you don’t make the connection and misunderstand what this code is doing.

How should it look then to be more elegant?

# sleeps for 3 seconds, then prints 615
f = future { sleep 3; 123}
puts f * 5

So, this is way more elegant! You see it is a future, because it says so! If you don’t know about futures, there is Wikipedia or Google and you might figure out what it does.

In order to make this happen, we need to define a future method that returns an object that when called returns Thread#value for that future. A proxy object. This leads to the next implementation:

class Proxy
 def initialize(&block)
   @thread = Thread.new(&block)
 end

 def method_missing(*args, &block)
   @thread.value.send(*args, &block)
 end
end

def future(&block)
 Proxy.new(&block)
end

f = future { sleep 3; 123}
puts f * 5

We created a Proxy class to do the threading logic and use method_missing to capture method calls, which we re-direct to Thread#value.

This works as long as you don’t call methods defined on Object or Kernel, because you get those for free in every class. You need to either avoid using them or get rid of them. There is BlankSlate, but since we were just trying to make our idea work, we just un-defined most methods on the object. Then we had the crazy idea to drop the Proxy object altogether and make Thread function as its own Proxy object. Thread, say bye-bye to your methods!

Here is the final bit of code we produced:

Then the library closed so we went home, after which I polished it a bit and created a github project for it.

This morning my colleague, Filip Slagter, asked me if there wasn’t already a library to do futures in Ruby. After a bit of searching, I found there is one. And it looks nice! Still, I like to re-invent the wheel. It is the best way to learn how something works.

Comments