Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

`return` in main environment

When I run the following in the main environment in irb or pry,

return "foo"

I get:

LocalJumpError: unexpected return

which is expected. But when I write this code in a separate file foo.rb, and do:

$ ruby foo.rb

in the console, it terminates without any error message.

What is happening in the latter case?

I thought a raised error might be silently disposed with, and tried the following in a separate file:

begin
  return "foo"
rescue Exception => e
  p e
end

and executed it from the console, but this also resulted in no error.

When I put the code in an environment such as a module, it returns the error:

module A
  return "foo" # >> Invalid return in class/module body
end
like image 411
sawa Avatar asked Jun 08 '26 05:06

sawa


1 Answers

Top-level return was added as a feature in ruby 2.4.0: https://bugs.ruby-lang.org/issues/4840

It was never mentioned in the release announcement, but you can see it listed under the "language changes" in the more detailed news post.

If you run a file which contains return "foo" in ruby version < 2.4.0, you will indeed see an error like:

foo.rb:1:in `<main>': unexpected return (LocalJumpError)

The intended use case (as you can see from the above link) was for "cancelling a require" - e.g. if the file is platform-specific, such as:

require "test/unit"

return unless /mswin|cygwin|mingw|bccwin/

# ...

There was much discussion and debate over proposed syntax and behaviour; but the chosen implementation can perhaps be best understood by reading the implementation's test cases:

def test_return_toplevel
  feature4840 = '[ruby-core:36785] [Feature #4840]'
  code = <<~'CODE'
  return; raise
  begin return; rescue SystemExit; exit false; end
  begin return; ensure exit false; end
  begin ensure return; end
  begin raise; ensure; return; end
  begin raise; rescue; return; end
  return false; raise
  return 1; raise
  CODE
  all_assertions(feature4840) do |a|
    code.each_line do |s|
      s.chomp!
      a.for(s) {assert_ruby_status([], s)}
    end
  end
end

Since writing return inside a REPL like pry is not at the "top level", this results in a LocalJumpError instead of the above special behaviour for "top-level return".

like image 67
Tom Lord Avatar answered Jun 10 '26 04:06

Tom Lord



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!