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
blockbegin
raise
rescue
nil
endAs 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
Read and Write Yaml Files Without Destroying Anchors and Aliases
Ruby: Class Instance Variables VS Instance Variables
Setspeed in Selenium Webdriver Using Ruby
What's the Precedence of Ruby'S Method Call
How to Avoid Trailing Empty Items Being Removed When Splitting Strings
Total Newbie: Instance Variables in Ruby
Why Do Two Strings Separated by Space Concatenate in Ruby
Ruby: Problem Installing Eventmachine Under Windows 7
Idiomatic Object Creation in Ruby
How to Change the Default Path of View Files in a Rails 3 Controller
How to Use Global Variables or Constant Values in Ruby
How to Remove Blank Elements from an Array
Ruby - Net/Http - Following Redirects
Ruby/Rails - Change the Timezone of a Time, Without Changing the Value