Does Ruby's $! hold value only in rescue block?
Asked Answered
M

2

11
begin
  raise 'foo'
rescue
  puts $!.inspect # => #<RuntimeError: foo>
ensure
  puts $!.inspect # => nil
end
puts $!.inspect # => nil

Googled around but didn't find a clear answer.

Just want to confirm the life-time(?) of $!, does it hold value only inside a rescue block?

Mcfarlane answered 9/1, 2015 at 1:51 Comment(3)
I believe so, but I can't seem to confirm it.Coffelt
Your ensure line and the line following it is making it more complex than needed.Dumfound
remove the rescue block and check it with just an ensure ...Hydrocele
O
15

$! has the error in the rescue block, or in the the ensure block if there's no rescue block:

begin
  raise 'foo'
ensure
  puts $!.inspect # => #<RuntimeError: foo>
end

$! has the value nil everywhere else.

Opuscule answered 9/1, 2015 at 6:14 Comment(2)
Thx! good to know. Probably will accept this as answer, just wait for one more day to be sure.Mcfarlane
Your answer was definitely more concise than mine, while saying the same thing.Genista
G
1

Edit: Original question was:

Is Ruby's $! value only visible in rescue block?

   begin
     raise 'foo'
   rescue
     puts $!.inspect # => #<RuntimeError: foo>
   end
   puts $!.inspect # => nil

Googled around but didn't find a clear answer.

Just want to confirm the visibility of $!, is it only accessible inside a rescue block?

No, the read only variable $! is visible and available every where, and holds the value of nil except in rescue blocks.

It is also unique to each thread. It is the current exception (the English library calls it $ERROR_INFO), and it is reset to nil once rescued, unless it is re-raised, then it is back to being the current exception.

From a file that has no other lines in it, we can see that indeed $! is visible.

puts defined?($!)
puts $!.inspect  

irb(main):001:0> defined?($!)
=> "global-variable"
irb(main):002:0> $!
=> nil
irb(main):003:0>

And in IRB we can see that it is defined and visible.

This really is not (or rather should not be) surprising at all, as the $ designates that it is "global variable" and as such is globally visible.

I have not been able to find where it is not visible. Even in BasicObject, it is visible.

irb(main):001:0> class BasicObject
irb(main):002:1>   def is_it_visible
irb(main):003:2>     defined?($!)                                                                                                 
irb(main):004:2>   end                                                                                                            
irb(main):005:1> end                                                                                                              
=> :is_it_visible
irb(main):006:0> BasicObject.allocate.is_it_visible
=> "global-variable"
irb(main):007:0>

I should add that it is one of the "read only" variables as well. Trying to assign to it would result in a NameError with a message explaining that it is a read-only variable.

Genista answered 9/1, 2015 at 8:19 Comment(3)
sorry, my wording seems confused you. I should ask "does $! only hold value inside rescue block?".Mcfarlane
No, your question was very clear. Nothing confusing to me about it at all. It holds the value of nil outside of those blocks, as you demonstrate in your code.Genista
To clarify, since the question changed, this is in answer to the original question, which was clear. This is, clearly, not the answer to the edited question.Genista

© 2022 - 2024 — McMap. All rights reserved.