views:

841

answers:

5

Hi,

I've recently started programming in Ruby, and I am looking at exception handling.

I was wondering if ensure was like finally in c#. So if I have the following:

file = File.open("myFile.txt", "w")

begin
file << "#{content} \n"
rescue
#handle the error here
ensure
file.close unless file.nil?
end

or should I do this?

#store the file
file = File.open("myFile.txt", "w")

begin
file << "#{content} \n"
file.close
rescue
#handle the error here
ensure
file.close unless file.nil?
end

What I am basically asking is, does ensure get called no matter what, even if an exception isn't raised.

Regards,

Lloyd

+1  A: 

Yes, ensure is called in any circumstances. For more information see this chapter of the Programming Ruby book (search for "ensure").

Milan Novota
+2  A: 

If you want to ensure a file is closed you should rather use the block form of File.open

File.open("myFile.txt", "w") do |file|
  begin
    file << "#{content} \n"
  rescue
  #handle the error here
  end
end
Farrel
A: 

Yes, ensure like finally guarantees that the block will be executed. Very useful for making sure that critical resources are protected e.g. close a file handle on error, release a mutex.

Chris McCauley
A: 

Yes. ensure ENSURES it is run every time. So you don't need the file.close in the begin block.

By the way, a good way to test is to do:

begin
  # Raise an error here
  raise "Error!!"
rescue
  #handle the error here
ensure
  p "=========inside ensure block"
end

You can test to see if "=========inside ensure block" will be printed out when there is an exception. Then you can comment out the statement that raises error and see if ensure statement is executed by seeing if anything gets printed out.

Aaron Qian
+19  A: 

Yes, ensure ensures that the code is always evaluated. That's why it's called ensure. So, it is equivalent to Java's and C#'s finally.

The general flow of begin/rescue/else/ensure/end looks like this:

begin
  # something which might raise an exception
rescue SomeExceptionClass => some_variable
  # code that deals with some exception
rescue SomeOtherException => some_other_variable
  # code that deals with some other exception
else
  # code that runs only if *no* exception was raised
ensure
  # ensure that this code always runs, no matter what
end

You can leave out rescue, ensure or else. You can also leave out the variables in which case you won't be able to inspect the exception in your exception handling code. (Well, you can always use the global exception variable to access the last exception that was raised, but that's a little bit hacky.) And you can leave out the exception class, in which case all exceptions that inherit from StandardError will be caught. (Please note that this does not mean that all exceptions are caught, because there are exceptions which are instances of Exception but not StandardError. Mostly very severe exceptions that compromise the integrity of the program such as SystemStackError, NoMemoryError, SecurityError, NotImplementedError, LoadError, SyntaxError, ScriptError, Interrupt, SignalException or SystemExit.)

Some blocks form implicit exception blocks. For example, method definitions are implicitly also exception blocks, so instead of writing

def foo
  begin
    # ...
  rescue
    # ...
  end
end

you write just

def foo
  # ...
rescue
  # ...
end

The same applies to class definitions and module definitions.

However, in the specific case you are asking about, there is actually a much better idiom. In general, when you work with some resource which you need to clean up at the end, you do that by passing a block to a method which does all the cleanup for you. It's similar to a using block in C#, except that Ruby is actually powerful enough that you don't have to wait for the high priests of Microsoft to come down from the mountain and graciously change their compiler for you. In Ruby, you can just implement it yourself:

# This is what you want to do:
File.open('myFile.txt', 'w') do |file|
  file.puts content
end

# And this is how you might implement it:
def File.open(filename, mode='r', perm=nil, opt=nil)
  yield filehandle = new(path, mode, perm, opt)
ensure
  filehandle.close
end

And what do you know: this is already available in the core library as File.open. But it is a general pattern that you can use in your own code as well, for implementing any kind of resource cleanup (à la using in C#) or transactions or whatever else you might think of.

The only case where this doesn't work, if acquiring and releasing the resource are distributed over different parts of the program. But if it is localized, as in your example, then you can easily use these resource blocks.


BTW: in modern C#, using is actually superfluous, because you can implement Ruby-style resource blocks yourself:

class File
{
    static T open<T>(string filename, string mode, Func<File, T> block)
    {
        var handle = new File(filename, mode);
        try
        {
            return block(handle);
        }
        finally
        {
            handle.Dispose();
        }
    }
}

// Usage:

File.open("myFile.txt", "w", (file) =>
{
    file.WriteLine(contents);
});
Jörg W Mittag
+1 for "wrote a chapter to a pretty good Ruby book."
Wayne Conrad