How Does One Use Rescue in Ruby Without the Begin and End Block

How does one use rescue in Ruby without the begin and end block

A method "def" can serve as a "begin" statement:

def foo
...
rescue
...
end

Are there unintended consequences of Ruby's `begin ... end` without `rescue` used as a code block?

I use this sometimes if I want to assign something to a variable but I have to calculate the value I want to assign first. It makes the code a little bit more tidy this way. I think it's user preference. Basically you are saying: I am assigning something to foo, but in order to get the value I want I first need to do some things. It's particularly useful when doing memoization, so instead of

if @cache.nil?
do_something!
@cache = read_value
end

You can do

@cache ||= begin
do_something!
read_value
end

What you are taking advantage here is that the Ruby interpreter has a stack, and each expression will usually push something on the stack, or take something from the stack. Assignment just takes the last thing from the stack and assigns it (in this case the last line from begin/end). Many times knowing this (stack approach in Ruby) can be useful.

I don't think it violates least surprise though, I think it's user preference wheather you want to use it or not.

You can see that it doesn't do anything unexpected by looking at what bytecode instructions it generates in Ruby MRI 1.9:

 RubyVM::InstructionSequence::compile("c = begin; a = 5; 6; end").to_a

[:trace, 1],
[:trace, 1],
[:putobject, 5],
[:setlocal, 2],
[:trace, 1],
[:putobject, 6],
[:dup],
[:setlocal, 3],
[:leave]

Trace is just for stack traces, you can ignore that. Dup duplicates the last item on the stack. In this example the number of the local variable a is 2 and the number of the local variable c is 3 (hence putobject, 2 will assign to variable a, etc).
The only side-effect of this compared to a = 5; c = 6 is the dup instruction, which means the stack size of your method will be larger by 1 slot. But this is not particularly important because it only has any effect while the interpreter is inside this particular method, and memory for stack is pre-reserved anyway, so it only means the stack pointer will be decremented by 1 more than it would otherwise. So basically no change at all. With optimizations turned on even the dup will probably disappear.

In Ruby, What structures can a `rescue` statement be nested in

You can only use rescue in two cases:

  • Within a begin ... end block

    begin
    raise
    rescue
    nil
    end
  • As a statement modifier

    i = raise rescue nil

Function, module, and class bodies (thanks Jörg) are implicit begin...end blocks, so you can rescue within any function without an explicit begin/end.

    def foo
raise
rescue
nil
end

The block form takes an optional list of parameters, specifying which exceptions (and descendants) to rescue:

    begin
eval string
rescue SyntaxError, NameError => boom
print "String doesn't compile: " + boom
rescue StandardError => bang
print "Error running script: " + bang
end

If called inline as a statement modifier, or without argument within a begin/end block, rescue will catch StandardError and its descendants.

Here's the 1.9 documentation on rescue.

Can I put retry in rescue block without begin ... end?

To answer the question you're asking, no. rescue can only be used from within a begin..end block or method body.

begin
bad_method
rescue SomeException
retry
end

def some_method
bad_method
rescue SomeException
retry
end

rescue_from is just a framework helper method created because of how indirect the execution is in a controller.

To answer the question you're really asking, sure. You can override create_or_update with a rescue/retry.

module NonUniquePkeyRecovery
def create_or_update(*)
super
rescue ActiveRecord::RecordNotUnique => e
raise unless e.message.include? '_pkey'
self.class.connection.reset_pk_sequence!(self.class.table_name)
retry
end
end

ActiveSupport.on_load(:active_record) do
include NonUniquePkeyRecovery
end

What is the purpose of using ruby begin without rescue?

This example is just bad - for the described case, there is no difference in behavior (and the bytecode will look very similar if not the same).

begin ... end block can be used for grouping several expressions - for example, for memoizing the intermediate result of some heavy calculations without additional intermediate assignments, like

some_var = begin
# a bunch of expressions goes there
end

# continue calculations using some_var

Actually, begin ... end block acts in pretty much the same way as def ... end does to define a method. And because of this similarity begin .... end is not used very often in the production code - in most practical cases it's better to move the group of closely related expressions into a separate method.

There is one case when this block can make the difference - consider

some_method while false

vs

begin
some_method
end while false

In the former snippet some_method isn't called at all, while in the latter it will be called once. But this usage is kind of discouraged - it makes the code trickier (the same can be done in a much more readable way with loop and explicit break)

Begin, Rescue and Ensure in Ruby?

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
# does not change the final value of the block
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

or

def foo
# ...
ensure
# ...
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(filename, 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);
});

Ruby begin rescue end with if-then-else

If you want to terminate the program (instead of just returning from fn2?), you can use Kernel#exit, for example:

begin
<do action>
rescue
<handle error here>
puts "Message 3"
exit(1)
end


Related Topics



Leave a reply



Submit