Ruby equivalent of C# "using keword" and IDispose

What is the most expedient way to do this C# construct in Ruby?

C#: using (myObj = new MyClass()) {
    // misc code here
} //MyClass.Dispose automatically called here

I wish to put stuff in MyClass.Dispose() to release resources... it must
always be called.

Pete

···

--
Posted via http://www.ruby-forum.com/.

You want "ensure". See
http://blog.rubybestpractices.com/posts/rklemme/001-Using_blocks_for_Robustness.html
http://blog.rubybestpractices.com/posts/rklemme/002_Writing_Block_Methods.html

Kind regards

robert

···

2010/1/21 Peter Alvin <form@awebabove.com>:

What is the most expedient way to do this C# construct in Ruby?

C#: using (myObj = new MyClass()) {
// misc code here
} //MyClass.Dispose automatically called here

I wish to put stuff in MyClass.Dispose() to release resources... it must
always be called.

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Peter Alvin wrote:

What is the most expedient way to do this C# construct in Ruby?

C#: using (myObj = new MyClass()) {
    // misc code here
} //MyClass.Dispose automatically called here

I wish to put stuff in MyClass.Dispose() to release resources... it must
always be called.

In a language with higher-order procedures like Ruby, adding a special
language construct for this is completely unnecessary. You just write
a method which accepts a piece of code as an argument, acquires the
resource, runs the piece of code and subsequently releases the
resource. This is the well-known "with-foo" pattern from Lisp,
basically. In Ruby, we generally use a factory-ish class method like
so:

    class DatabaseConnection
      def self.use(*args)
        yield handle = new(*args)
      ensure
        handle.close
      end
    end

This is how usage would look like:

    DatabaseConnection.use('/path/to/sqlite.db') do |conn|
      conn.exec 'SELECT blah FROM blurb WHERE foo = 42;'
      conn.exec 'INSERT something INTO somewhere;'
    end

This pattern is for example used by IO.open in the standard library:

    File.open('/path/to/file', 'w+') do |f|
      f.puts 'Hello, World'
    end

The two main differences between the two methods are:

* in the Ruby version, the acquisition of the resource is hidden away
    inside the method, whereas in C#, the user is responsible for
    creating the resource. (You could, of course, write a generic
    method that simply takes any resource as a parameter. That's just
    not the normal style in Ruby.)
* in the C# version, there is a standardized agreement over what the
    name of the method for releasing the resource is (the Dispose()
    pattern) and there is even a type for it (the IDisposable
    interface)

Here's what a more C# style implementation in Ruby would look like:

    def using(handle)
      yield handle
    ensure
      handle.dispose
    end

    using(MyClass.new) do |my_obj|
      # misc code here
    end # MyClass#dispose automatically called here

BTW: you can do that in C#, too, now. It's just that before lambda
expressions, local variable type inference and anonymous types were
introduced in C#, it would have been a lot of typing (in both senses
of the word). This is what the opposite would look like (i.e. Ruby
style implemented in C#):

    class DatabaseConnection
    {
        static T use<T>(string connection, Func<DatabaseConnection, T> block)
        {
            var handle = new DatabaseConnection(connection);
            try
            {
                return block(handle);
            }
            finally
            {
                handle.Dispose();
            }
        }
    }

And this is how you use it:

    DatabaseConnection.use("/path/to/db", (conn) =>
    {
        // misc code here
    }); // MyClass.Dispose automatically called here

(If you don't want to return a value, lose the T and replace Func with
Action.)

jwm

I finally came up with this toy:

def using(res, options = { release_with: :close })
  yield res
ensure
  if res.respond_to?(options[:release_with])
    res.send(options[:release_with])
  end
end

With using method, you can have C# style coding as follows:

using(db = SQLite3::Database.new('cart.db')) {
  # ...
}

Or you can make use of the block parameter:

using(SQLite3::Database.new('cart.db')) { |db|
  # ...
}

If, however, the resource you are about to use favers a different method to
release, you can also specify it to using:

using(SQLite3::Database.new('cart.db'), release_with: "close") { |db|
  # ...
}

Note that you need to go back to :release_with => "close" if you are
targeting version before 1.9.

Enjoy!

allen

2010/1/22 Jörg W Mittag
<JoergWMittag+Ruby@googlemail.com<JoergWMittag%2BRuby@googlemail.com>

···

Peter Alvin wrote:
> What is the most expedient way to do this C# construct in Ruby?
>
> C#: using (myObj = new MyClass()) {
> // misc code here
> } //MyClass.Dispose automatically called here
>
> I wish to put stuff in MyClass.Dispose() to release resources... it must
> always be called.

In a language with higher-order procedures like Ruby, adding a special
language construct for this is completely unnecessary. You just write
a method which accepts a piece of code as an argument, acquires the
resource, runs the piece of code and subsequently releases the
resource. This is the well-known "with-foo" pattern from Lisp,
basically. In Ruby, we generally use a factory-ish class method like
so:

   class DatabaseConnection
     def self.use(*args)
       yield handle = new(*args)
     ensure
       handle.close
     end
   end

This is how usage would look like:

   DatabaseConnection.use('/path/to/sqlite.db') do |conn|
     conn.exec 'SELECT blah FROM blurb WHERE foo = 42;'
     conn.exec 'INSERT something INTO somewhere;'
   end

This pattern is for example used by IO.open in the standard library:

   File.open('/path/to/file', 'w+') do |f|
     f.puts 'Hello, World'
   end

The two main differences between the two methods are:

* in the Ruby version, the acquisition of the resource is hidden away
   inside the method, whereas in C#, the user is responsible for
   creating the resource. (You could, of course, write a generic
   method that simply takes any resource as a parameter. That's just
   not the normal style in Ruby.)
* in the C# version, there is a standardized agreement over what the
   name of the method for releasing the resource is (the Dispose()
   pattern) and there is even a type for it (the IDisposable
   interface)

Here's what a more C# style implementation in Ruby would look like:

   def using(handle)
     yield handle
   ensure
     handle.dispose
   end

   using(MyClass.new) do |my_obj|
     # misc code here
   end # MyClass#dispose automatically called here

BTW: you can do that in C#, too, now. It's just that before lambda
expressions, local variable type inference and anonymous types were
introduced in C#, it would have been a lot of typing (in both senses
of the word). This is what the opposite would look like (i.e. Ruby
style implemented in C#):

   class DatabaseConnection
   {
       static T use<T>(string connection, Func<DatabaseConnection, T>
block)
       {
           var handle = new DatabaseConnection(connection);
           try
           {
               return block(handle);
           }
           finally
           {
               handle.Dispose();
           }
       }
   }

And this is how you use it:

   DatabaseConnection.use("/path/to/db", (conn) =>
   {
       // misc code here
   }); // MyClass.Dispose automatically called here

(If you don't want to return a value, lose the T and replace Func with
Action.)

jwm

I finally came up with this toy:

This looks interesting. Although I have to say that the functionality
should be rather built into the classes at hand (like e.g. File has)
IMHO.

def using(res, options = { release_with: :close })

Since you have a single option only you can as well do

def using(res, close = :close)

yield res
ensure
if res.respond_to?(options[:release_with])
res.send(options[:release_with])
end

I'd rather do

  res.send(options[:release_with]) rescue nil

Because the idea of respond_to? and what the class really understands
may differ.

irb(main):001:0> class X
irb(main):002:1> def method_missing(s,*a,&b)
irb(main):003:2> "I can #{s}!"
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> o = X.new
=> #<X:0x101596fc>
irb(main):007:0> o.respond_to? :dance
=> false
irb(main):008:0> o.dance
=> "I can dance!"
irb(main):009:0> o.dance!
=> "I can dance!!"
irb(main):010:0>

end

Note that you need to go back to :release_with => "close" if you are
targeting version before 1.9.

This is not necessary if you just use a single additional parameter (see above).

Kind regards

robert

···

2010/1/22 Allen Lee <allenlooplee@gmail.com>:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

1) I also considered

def using(res, close = :close)

over

def using(res, options = { release_with: :close })

however, I think

using(Res.new, release_with: "close")

would be nicer than

using(Res.new, "close")

so finally I chose what it is right now :slight_smile:

2) The solution you provided as follows is definitely more robust due to
respond_to? may not work as expected in the situation you mentioned and
thanks!

res.send(options[:release_with]) rescue nil

allen

···

On Fri, Jan 22, 2010 at 5:32 PM, Robert Klemme <shortcutter@googlemail.com>wrote:

2010/1/22 Allen Lee <allenlooplee@gmail.com>:
> I finally came up with this toy:

This looks interesting. Although I have to say that the functionality
should be rather built into the classes at hand (like e.g. File has)
IMHO.

> def using(res, options = { release_with: :close })

Since you have a single option only you can as well do

def using(res, close = :close)

> yield res
> ensure
> if res.respond_to?(options[:release_with])
> res.send(options[:release_with])
> end

I'd rather do

res.send(options[:release_with]) rescue nil

Because the idea of respond_to? and what the class really understands
may differ.

irb(main):001:0> class X
irb(main):002:1> def method_missing(s,*a,&b)
irb(main):003:2> "I can #{s}!"
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> o = X.new
=> #<X:0x101596fc>
irb(main):007:0> o.respond_to? :dance
=> false
irb(main):008:0> o.dance
=> "I can dance!"
irb(main):009:0> o.dance!
=> "I can dance!!"
irb(main):010:0>

> end
>
> Note that you need to go back to :release_with => "close" if you are
> targeting version before 1.9.

This is not necessary if you just use a single additional parameter (see
above).

Kind regards

robert

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/