Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby Syntax of '=>' (hashrocket)

Tags:

syntax

ruby

I tried this earlier and everyone got off on rescue block syntax. Please don't go there. Given the following working code:

begin
  (1..1000).each do |i|
    puts i
    sleep 1
  end
rescue Exception => e
   puts "\nCaught exception..."
   puts "Exception class: #{e.class}"
end

Pressing CTRL+C while it is running prints out "Caught exception...", as expected. What exactly is going on syntax wise in the rescue line, particularly between Exception and the variable e with the => in between?

The word "rescue" is a keyword... part of the ruby language. "e" is a variable, and could just as functionally be "a", "b", or "c". The following code works just as well.

begin
  (1..1000).each do |i|
    puts i
    sleep 1
  end
rescue Exception => b
   puts "\nCaught exception..."
   puts "Exception class: #{b.class}"
end

What are "Exception" and "=>"? Is there another way to write this expression to make it more intelligible from a syntactical point of view? I don't think we're dealing with a hash here because the following code compiles but throws an error as soon as CTRL+C is pressed (undefined local variable or method `e').

begin
  (1..1000).each do |i|
    puts i
    sleep 1
  end
rescue { Exception => b }
   puts "\nCaught exception..."
   puts "Exception class: #{b.class}"
end

Can someone explain what is going on? and specifically what language element '=>' (hashrocket) is in this specific example since it seems to have nothing to do with hashes?

like image 484
user8116088 Avatar asked Jun 08 '18 20:06

user8116088


Video Answer


1 Answers

I'm sorry to inform you that this is just one-off syntax that doesn't really have any relation to other Ruby syntax.

Given the expression:

begin
  # ...
rescue FooError, BarError => ex
  # ...
end
  • FooError, BarError is the list of exception classes (usually subclasses of StandardError) that will be rescued. This behaves just like an argument list, so you can (if you want) do stuff like this:

    my_exception_classes = [ FooError, BarError ]
    
    begin
      # ...
    rescue *my_exception_classes => ex
      # ...
     end
    

    It's worth noting that you shouldn't, generally, use Exception here because it will rescue all exceptions, including things like SignalException::Interrupt and NoMemoryError, which usually isn't what you want.

  • => is just syntax, and arguably not the best choice of syntax for the reason that it leads to questions like your own.

  • ex is the name of a local variable into which the exception object will be put.

Digging deeper

If you're into reading parser grammars, it's always fun looking at Ruby's YACC grammar in parse.y. It's not especially easy to read, but we can see the grammar for a rescue expression, called opt_rescue in the grammar, here:

opt_rescue  : k_rescue exc_list exc_var then
              compstmt
              opt_rescue

k_rescue is of course the keyword rescue. exc_list is the list of exception classes which, like I said, is just like an argument list:

exc_list    : arg_value

exc_var is the part where the variable to put the exception in is designated:

exc_var     : tASSOC lhs

And here, tASSOC is of course our friend the hashrocket (=>), and lhs, i.e. “left-hand side,” is an expression you'd find to the left of an assignment expression (like, say, the name of a variable).

compstmt is basically “any valid Ruby code,” and then there’s opt_rescue again, since you can (optionally) have many rescues in a begin or def block.

As you can see, the only thing this syntax has in common with a Hash is tASSOC.

like image 187
Jordan Running Avatar answered Sep 19 '22 16:09

Jordan Running