A
Adam Sanderson
I was looking at the Io documentation, just to see what the language
looked like and saw the asynchronous support, pretty cool. Then it
sort of dawned on my how Futures worked, no it isn't all that
complicated, but I it's amazing what you can avoid thinking about. Who
knows, I think looking into the gaze of a new language, and reading too
much of _why's Redhanded is likely to provide random inspiration. So
here is a quick implementation of transparent futures in ruby. Two
questions:
1. Is it worth tossing this on RubyForge or some such place?
2. I'd like to use BlankSlate, but it's part of Builder, but it seems
silly for this to depend on all of the Builder gem, so for demo
purposes BlankSlate is pasted in and taken out of the Builder
namespace.
To try it out do something like this:
require 'future'
f = Future.new{sleep 5; 10} # Returns immediately
f + 1 # 11 after a pause
.adam
#--
# Copyright 2004 by Jim Weirich ([email protected]).
# All rights reserved.
# Permission is granted for use, copying, modification, distribution,
# and distribution of modified versions of this work as long as the
# above copyright notice is included.
#++
# BlankSlate provides an abstract base class with no predefined
# methods (except for <tt>\_\_send__</tt> and <tt>\_\_id__</tt>).
# BlankSlate is useful as a base class when writing classes that
# depend upon <tt>method_missing</tt> (e.g. dynamic proxies).
class BlankSlate #:nodoc:
class << self
def hide(name)
undef_method name if
instance_methods.include?(name.to_s) and
name !~ /^(__|instance_eval)/
end
end
instance_methods.each { |m| hide(m) }
end
# Since Ruby is very dynamic, methods added to the ancestors of
# BlankSlate <em>after BlankSlate is defined</em> will show up in the
# list of available BlankSlate methods. We handle this by defining a
hook in the Object and Kernel classes that will hide any defined
module Kernel #:nodoc:
class << self
alias_method :blank_slate_method_added, :method_added
def method_added(name)
blank_slate_method_added(name)
return if self != Kernel
BlankSlate.hide(name)
end
end
end
class Object #:nodoc:
class << self
alias_method :blank_slate_method_added, :method_added
def method_added(name)
blank_slate_method_added(name)
return if self != Object
BlankSlate.hide(name)
end
end
end
# Future
# Adam Sanderson fooling around on 2006-01-07
class Future < BlankSlate
def initialize(*args, &block)
@__thread = Thread.new do
@__value = block.call(*args)
end
end
def __getobj__
if @__thread
@__thread.join
@__thread = nil
end
@__value
end
def method_missing(sym, *args, &block)
__getobj__.send sym, *args, &block
end
def inspect
(@__thread) ? "Unevaluated Future on #{@__thread.inspect}" :
@__value.inspect
end
end
looked like and saw the asynchronous support, pretty cool. Then it
sort of dawned on my how Futures worked, no it isn't all that
complicated, but I it's amazing what you can avoid thinking about. Who
knows, I think looking into the gaze of a new language, and reading too
much of _why's Redhanded is likely to provide random inspiration. So
here is a quick implementation of transparent futures in ruby. Two
questions:
1. Is it worth tossing this on RubyForge or some such place?
2. I'd like to use BlankSlate, but it's part of Builder, but it seems
silly for this to depend on all of the Builder gem, so for demo
purposes BlankSlate is pasted in and taken out of the Builder
namespace.
To try it out do something like this:
require 'future'
f = Future.new{sleep 5; 10} # Returns immediately
f + 1 # 11 after a pause
.adam
#--
# Copyright 2004 by Jim Weirich ([email protected]).
# All rights reserved.
# Permission is granted for use, copying, modification, distribution,
# and distribution of modified versions of this work as long as the
# above copyright notice is included.
#++
# BlankSlate provides an abstract base class with no predefined
# methods (except for <tt>\_\_send__</tt> and <tt>\_\_id__</tt>).
# BlankSlate is useful as a base class when writing classes that
# depend upon <tt>method_missing</tt> (e.g. dynamic proxies).
class BlankSlate #:nodoc:
class << self
def hide(name)
undef_method name if
instance_methods.include?(name.to_s) and
name !~ /^(__|instance_eval)/
end
end
instance_methods.each { |m| hide(m) }
end
# Since Ruby is very dynamic, methods added to the ancestors of
# BlankSlate <em>after BlankSlate is defined</em> will show up in the
# list of available BlankSlate methods. We handle this by defining a
hook in the Object and Kernel classes that will hide any defined
module Kernel #:nodoc:
class << self
alias_method :blank_slate_method_added, :method_added
def method_added(name)
blank_slate_method_added(name)
return if self != Kernel
BlankSlate.hide(name)
end
end
end
class Object #:nodoc:
class << self
alias_method :blank_slate_method_added, :method_added
def method_added(name)
blank_slate_method_added(name)
return if self != Object
BlankSlate.hide(name)
end
end
end
# Future
# Adam Sanderson fooling around on 2006-01-07
class Future < BlankSlate
def initialize(*args, &block)
@__thread = Thread.new do
@__value = block.call(*args)
end
end
def __getobj__
if @__thread
@__thread.join
@__thread = nil
end
@__value
end
def method_missing(sym, *args, &block)
__getobj__.send sym, *args, &block
end
def inspect
(@__thread) ? "Unevaluated Future on #{@__thread.inspect}" :
@__value.inspect
end
end