IDisposable in Ruby
over 17 years ago
I have been learning Ruby lately and have been very impressed with a language feature called code blocks.
Essentially it allows any method to return control and optionally data to the caller. It is used to implement iterators, transactions, profiling blocks etc…
So, I decided to see if it could be applied to the problem IDisposable was created to solve.
Take the following C# code:
class Tester : IDisposable
{
public Tester()
{
Console.WriteLine("Allocating");
}
public void DoStuff()
{
Console.WriteLine("doing stuff");
}
public void Dispose()
{
Console.WriteLine("Deallocating");
}
class Program
{
static void Main(string[] args)
{
try
{
using (Tester t = new Tester())
{
t.DoStuff()
throw new Exception("something happened");
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
This simple example has a pile of issues.
-
The designer of the “Tester” class has no way of ensuring that “Tester” objects are wrapped in using blocks (or at least always finally disposed)
-
This can be partially worked around by defining a finalizer, tracking weather the object is disposed or not and suppressing the finalizer if the object is disposed properly. It is a real headache.
-
The designer of the “Tester” object has no way of telling if the object was used successfully and no exceptions were thrown.
-
.NET has no mechanism for asking the framework if exception handling blocks are currently being executed.
I rewrote it in Ruby:
class Tester
def do_stuff()
puts "doing stuff"
end
def initialize()
raise "Must be called from a code block!" if !block_given?
begin
puts "Allocating resources"
yield self
rescue
puts "An exception happend: " + $!
raise
ensure
puts "Deallocating resources"
end
end
end
end
begin
Tester.new do |test|
test.do_stuff
raise "Something happened!"
end
rescue
puts "Caught: " + $!
end
end
Ruby’s advantages:
- You can trap and track exceptions during the cleanup phase.
- You can ensure proper usage. (Raises an exception if not used from a code block
- You need to write less code.
- It is a lot less mysterious. For someone new to .Net the relationship between the “using” keyword and the IDisposable interface may seem arbitrary.