Emulate C# Using Statement in Ruby

Posted by Andrew on September 27, 2007

Ruby is great language for creating DSLs. One reason why is that the syntax is expressive enough to create what look like new language features. As a simple example lets see how to create the Ruby equivalent of the C# Using statement. In C# the statement looks like this:

using (IDisposable foo = new DisposableImpl())
{
  // do something with foo
}

The semantics of the statement are:

  • foo must implement the IDisposable interface.
  • foo.Dispose() is guaranteed to be called when the statement terminates.

So in Ruby we would want something like this:

require 'using'
 
class Foo
  def dispose
    puts "Disposing"
  end
end
 
using (foo = Foo.new) {
  puts "Inside using"
}

When we run this we get:

RubyMate r6354 running Ruby r1.8.2 (/usr/bin/ruby)
>>> test.rb

Inside using
Disposing


So how do we implement this? Basically, we just create a new method on Object (the root of all Ruby objects) called “using” and then we exploit the fact that in Ruby any method can be passed an optional “block” of code as it’s last argument (think anonymous delegate or lambda in C#). The sugar here is that this last block argument actually appears after the closing parenthesis of the argument list. Nice.

class Object
  def using(o)
    begin
      yield if block_given?
    ensure
      o.dispose
    end
  end
end
Trackbacks

Use this link to trackback from your own site.

Comments

Leave a response

  1. Cedric VivierNo Gravatar Thu, 20 Dec 2007 15:24:22 CST

    Hey Andrew!

    Sure Ruby is nice, however we can also have this in .NET when using the Boo language :)

    using disposableObject = ObjectImplementingIDisposable():
    …do something

    boo having an extensible compiler, it is implemented as an AST macro like this ( [| ... |] constructs are used for meta-programming in Boo) :

    macro using:

    expansion = using.Block

    for expression as Expression in reversed(using.Arguments):

    temp = ReferenceExpression(”__using${_context.AllocIndex()}__”)

    assignment = [| $temp = $expression as System.IDisposable |].withLexicalInfoFrom(expression)

    expansion = [|

    $assignment

    try:

    $expansion

    ensure:

    if $temp is not null:

    $temp.Dispose()

    $temp = null

    |]

    return expansion

  2. AndrewNo Gravatar Thu, 20 Dec 2007 15:51:27 CST

    He Cedric,

    Boo is cool. Extending the compiler is very cool but I’m worried about the mainstream applicability of the technique :-)

    Andrew.

Comments