What value is returned when a method exits early on a return keyword with no argument? - ruby

Consider the following Ruby method:
def increment(value)
return if value >= 999
value + 1
end
What value gets returned to the caller from this method if the return statement executes?
From running this code myself, it appears that nil is returned. But is it always guaranteed to be the case that a return with no argument specified implicitly returns nil? Is this behavior documented somewhere? Is the behavior Ruby language version-dependent?
I checked several of the various sites linked to from https://www.ruby-lang.org/en/documentation/, including http://www.ruby-doc.org/docs/ProgrammingRuby/, without locating a definitive answer.

return is a Ruby keyword. From the documentation:
return Exits a method. See methods. If met in top-level scope, immediately stops interpretation of the current file.
From the return values section of the methods documentation:
By default, a method returns the last expression that was evaluated in the body of the method. ... The return keyword can be used to make it explicit that a method returns a value.
From The Ruby Programming Language by David Flanagan and Yukihiro Matsumoto (creator of the Ruby programming language), chapter 5.5.1 return:
return may optionally be followed by an expression, or a comma-separated list of expressions. If there is no expression, then the return value of the method is nil. If there is one expression, then the value of that expression becomes the return value of the method. If there is more than one expression after the return keyword, then the return value of the method is an array containing the values of those expressions.
This last passage can be considered the canonical answer, though I believe there may be additional information in ISO/IEC 30170 on this.
To clarify how using if as a modifier is evaluated by the interpreter in your example, I'll again quote The Ruby Programming Language, chapter 5.1.2 if As a Modifier:
When if is used in its normal statement form, Ruby’s grammar requires that it be terminated with the end keyword. For simple, single-line conditionals, this is somewhat awkward. This is just a parsing problem, and the solution is to use the if keyword itself as the delimiter that separates the code to be executed from the conditional expression. Instead of writing:
if expression then code end
we can simply write:
code if expression
When used in this form, if is known as a statement (or expression) modifier. If you’re a Perl programmer, you may be accustomed to this syntax. If not, please note that the code to execute comes first, and the expression follows. For example:
puts message if message # Output message, if it is defined
This syntax places more emphasis on the code to be executed, and less emphasis on the condition under which it will be executed. Using this syntax can make your code more readable when the condition is a trivial one or when the condition is almost always true.
Even though the condition is written last, it is evaluated first. If it evaluates to anything other than false or nil, then the code is evaluated, and its value is used as the return value of the modified expression. Otherwise, the code is not executed, and the return value of the modified expression is nil. Obviously, this syntax does not allow any kind of else clause.

According to ISO/IEC 30170, the return expression works like this: (the right-hand side being the returned value)
return #=> nil
return obj #=> obj
return a, b, c #=> [a, b, c]
Then there is return *obj which works like the splat operator in method calls, i.e. it converts obj to an argument list and returns that list as an array:
return *1..5 #=> [1, 2, 3, 4, 5]
The standard notes that if the resulting argument list has a size of 1 or 0, the return value is implementation-defined. So it could work like this:
return *[] #=> nil
return *[a] #=> a
return *[a, b] #=> [a, b]
However, the Ruby implementations I know always return an array when using *:
return *[] #=> []
return *[a] #=> [a]
return *[a, b] #=> [a, b]
Outside of a method invocation, return raises a LocalJumpError with a reason value of :return and an exit_value corresponding to the return value as described above.
You can find more examples and edge cases in the the Ruby Spec's language/return_spec.rb which also contains a test for a blank return:
it "returns nil by default" do
def r; return; end
r().should be_nil
end

Related

Ruby - what does Array.any?(&:nil?) mean?

I am new to ruby and working through a tutorial but am not sure what this line of code means:
[movie, version_number].any?(&:nil?)
From my research, Array.any? returns true if any of the elements of the array are not false or nil. And &:nil? means to call to_proc() on the symbol :nil? i.e. :nil?.to_proc so the statement is equivalent to
[movie, version_number].any?(:nil?.to_proc)
which is equivalent to
[movie, version_number].any?{|item| item.nil?}
Further, any? Passes each element of the collection (in this case, Array) to the {|item| item.nil?} block.
When you put them together, does the line of code mean, call nil? on each element in the Array before calling .any? on the array, i.e. is it equivalent to:
[movie.nil?, version_number.nil?].any?
Or, in plain English, are any of movie or version_number equivalent to nil?
From Symbol#to_proc documentation:
Returns a Proc object which respond to the given method by sym.
(1..3).collect(&:to_s) #=> ["1", "2", "3"]
So in your case this is effectively the same as writing:
[movie, version_number].any?{|item| item.nil? }
any? expects a block[1] to be passed, which will be evaluated for each item, and will return true if the block evaluates to true for any of the members.
The to_proc method on Symbol is basically a convenience shortcut, when you just want to call a single method on the item passed to the block. As in the example above, this leads to shorter code than explicitly defining the block.
[1] Refer this article on blocks, procs and lambdas in ruby

Simple way to understand returning from a block in ruby

My code is supposed to print integers in an array.
odds_n_ends = [:weezard, 42, "Trady Blix", 3, true, 19, 12.345]
ints = odds_n_ends.select { |x| if x.is_a?(Integer) then return x end }
puts ints
It gives me an error in the 2nd line - in 'block in <main>': unexpected return (LocalJumpError)
When I remove the return, the code works exactly as desired.
To find the mistake in my understanding of blocks, I read related posts post1 and post2. But, I am not able to figure out how exactly are methods and blocks being called and why my approach is incorrect.
Is there some call stack diagram explanation for this ? Any simple explanation ?
I am confused because I have only programmed in Java before.
You generally don't need to worry exactly what blocks are to use them.
In this situation, return will return from the outside scope, e.g. if these lines were in a method, then from that method. It's the same as if you put a return statement inside a loop in Java.
Additional tips:
select is used to create a copied array where only the elements satisfying the condition inside the block are selected:
only_ints = odds_n_ends.select { |x| x.is_a?(Integer) }
You're using it as a loop to "pass back" variables that are integers, in which case you'd do:
only_ints = []
odds_n_ends.each { |x| if x.is_a?(Integer) then only_ints << x end }
If you try to wrap your code in a method then it won't give you an error:
def some_method
odds_n_ends = [:weezard, 42, "Trady Blix", 3, true, 19, 12.345]
ints = odds_n_ends.select { |x| if x.is_a?(Integer) then return true end }
puts ints
end
puts some_method
This code output is true. But wait, where's puts ints??? Ruby didn't reach that. When you put return inside a Proc, then you're returning in the scope of the entire method. In your example, you didn't have any method in which you put your code, so after it encountered 'return', it didn't know where to 'jump to', where to continue to.
Array#select basically works this way: For each element of the array (represented with |x| in your code), it evaluates the block you've just put in and if the block evaluates to true, then that element will be included in the new array. Try removing 'return' from the second line and your code will work:
ints = odds_n_ends.select { |x| if x.is_a?(Integer) then true end }
However, this isn't the most Ruby-ish way, you don't have to tell Ruby to explicitly return true. Blocks (the code between the {} ) are just like methods, with the last expression being the return value of the method. So this will work just as well:
ints = odds_n_ends.select { |x| if x.is_a?(Integer) } # imagine the code between {} is
#a method, just without name like 'def is_a_integer?' with the value of the last expression
#being returned.
Btw, there's a more elegant way to solve your problem:
odds_n_ends = [:weezard, 42, "Trady Blix", 3, true, 19, 12.345]
ints = odds_n_ends.grep(Integer)
puts ints
See this link. It basically states:
Returns an array of every element in enum for which Pattern ===
element.
To understand Pattern === element, simply imagine that Pattern is a set (let's say a set of Integers). Element might or might not be an element of that set (an integer). How to find out? Use ===. If you type in Ruby:
puts Integer === 34
it will evalute to true. If you put:
puts Integer === 'hey'
it will evalute to false.
Hope this helped!
In ruby a method always returns it's last statement, so in generall you do not need to return unless you want to return prematurely.
In your case you do not need to return anything, as select will create a new array with just the elements that return true for the given block. As ruby automatically returns it's last statement using
{ |x| x.is_a?(Integer) }
would be sufficient. (Additionally you would want to return true and not x if you think about "return what select expects", but as ruby treats not nil as true it also works...)
Another thing that is important is to understand a key difference of procs (& blocks) and lambdas which is causing your problem:
Using return in a Proc will return the method the proc is used in.
Using return in a Lambdas will return it's value like a method.
Think of procs as code pieces you inject in a method and of lambdas as anonymous methods.
Good and easy to comprehend read: Understanding Ruby Blocks, Procs and Lambdas
When passing blocks to methods you should simply put the value you want to be returned as the last statement, which can also be in an if-else clause and ruby will use the last actually reached statement.

Best way to prevent returning last evaluated expression

Suppose I want to write a method in ruby whose last line is a method call but I do not want to return its return value. Is there a more elegant way to accomplish this other than adding a nil after the call?
def f(param)
# some extra logic with param
g(param) # I don't want to return the return of g
end
If you want to make it "poke you in the eye" explicit, just say "this method doesn't return anything":
def f(param)
# some extra logic with param
g(param) # I don't want to return the return of g
return
end
f(x) will still evaluate to nil but a bare return is an unambiguous way to say "this method doesn't return anything of interest", a trailing nil means that "this method explicitly returns nil" and that's not quite the same as not returning anything of use.
No, but if it is important that f indeed returns nil, and not whatever g(param) returns, then nothing is more elegant than spelling that out with a nil on the last line. Why would you want to obfuscate this away? Most of the time, elegance is in the explicit and the obvious.
A few tenants from The Zen of Python come to mind:
Explicit is better than implicit.
Simple is better than complex.
Readability counts.
No. If you want to return nil, the last expression has to evaluate to nil. You can do this with a terminating nil line or by surrounding the method body in nil.tap {} or however else you like, but it's pretty straightforward — the last expression evaluated gets returned.
As the others have said, no. However, if you want to avoid adding another line, you have a couple of options:
g(param); nil
g(param) && nil
The first will always cause f to return nil; the second will return false (if g returns false) or nil (if g returns a truthy value).
No, there is no other way than to either explicitly return nil or evaluate some other expression which implicitly evaluates to nil (e.g. ()).
If you want to add some kind of semantic marker that shows that you explicitly want to ignore the return value, you could invent some convention for that, e.g.:
def f(param)
# some extra logic with param
g(param) # I don't want to return the return of g
()
end
or
def f(param)
# some extra logic with param
g(param) # I don't want to return the return of g
_=_
end
which will make those cases easily grepable but probably won't aid much in understanding.
This is a design choice of Ruby which it shares with many other expression-based languages: the value of a block/subroutine/procedure/function/method is the value of the last expression evaluated inside the block. That's how it works in Lisp, for example.
Note that there are other choices as well. E.g. in Smalltalk, the return value of a method must be explicitly returned using the ↑ operator, otherwise the return value is nil. In E, which is heavily focused on security, this is even a conscious design choice: automatically returning the value of the last expression is considered a potential information leak.

ruby, define []= operator, why can't control return value?

Trying to do something weird that might turn into something more useful, I tried to define my own []= operator on a custom class, which you can do, and have it return something different than the value argument, which apparently you can't do. []= operator's return value is always value; even when you override this operator, you don't get to control the return value.
class Weird
def []=(key, value)
puts "#{key}:#{value}"
return 42
end
end
x = Weird.new
x[:a] = "a"
output "a:a"
return value => "a" # why not 42?
Does anyone have an explanation for this? Any way around it?
ruby MRI 1.8.7. Is this the same in all rubys; Is it part of the language?
Note that this behavior also applies to all assignment expressions (i.e. also attribute assignment methods: def a=(value); 42; end).
My guess is that it is designed this way to make it easy to accurately understand assignment expressions used as parts of other expressions.
For example, it is reasonable to expect x = y.a = z[4] = 2 to:
call z.[]=(4,2), then
call y.a=(2), then
assign 2 to the local variable x, then finally
yield the value 2 to any “surrounding” (or lower precedence) expression.
This follows the principle of least surprise; it would be rather surprising if, instead, it ended up being equivalent to x = y.a=(z.[]=(4,2)) (with the final value being influenced by both method calls).
While not exactly authoritative, here is what Programming Ruby has to say:
Programming Ruby (1.8), in the Expressions section:
An assignment statement sets the variable or attribute on its left side (the lvalue) to refer to the value on the right (the rvalue). It then returns that value as the result of the assignment expression.
Programming Ruby 1.9 (3rd ed) in section 22.6 Expressions, Conditionals, and Loops:
(right after describing []= method calls)
The value of an assignment expression is its rvalue. This is true even if the assignment is to an attribute method that returns something different.
It’s an assignment statement, and those always evaluate to the assigned value. Making this different would be weird.
I suppose you could use x.[]= :a, "a" to capture the return value.

Double ampersand in Ruby

I am using the authlogic gem with Ruby on Rails, and I have been using the following to obtain the id of the user that is currently logged in:
current_user = UserSession.find
id = current_user && current_user.record.id
I'm not understanding how current_user && current_user.record.id returns the current user id. I would think this would return a boolean. Can someone explain how this works?
There is no Boolean type in Ruby; Ruby has a rather simple view of truth (or more precisely, it has a rather simple view of falsehood).
the false object, which is the singleton instance of FalseClass is considered falsy
the nil object, which is the singleton instance of NilClass is falsy
every other object is truthy (including, obviously, the true object, which is the singleton instance of TrueClass)
[BTW: this means that a lot of objects that are considered falsy in some other languages, are actually truthy in Ruby, like the integer 0, the real value 0.0, the empty string, the empty array, the empty hash, the character 'F']
So, the Boolean operators &&, ||, and and or do not return Boolean values. Instead they return the first object that determines the outcome of the expression.
(They are also short-circuiting, which means that they only evaluate the minimum sub-expressions that are needed to determine the outcome of the expression. So, an alternate formulation would be that they return the result of the last expression that was evaluated. Which, in turn, is analogous to what blocks, methods, class bodies and module bodies do.)
So, what does it mean to return the first object that determines the outcome? That's simple, really: the result of the expression
a && b
is truthy if both a and b are truthy, otherwise it is falsy. So, if a is falsy, it is completely irrelevant what b is: the result will be falsy either way. So, we might just as well simply return a. (Remember, a doesn't have to be false, it could also be nil and the programmer might want to know which one of the two it was.)
If, OTOH, a is truthy (IOW it is neither nil nor false), then the result of the whole expression is solely dependent on b: if b is truthy, the whole result will be truthy, otherwise if b is falsy, the whole result will be falsy. So, we might just as well return b itself, instead of first converting it to a Boolean.
|| and or are analogous or more precisely dual to && and and.
You posted this example:
id = current_user && current_user.record.id
Here, the author isn't even expecting current_user to be a Boolean value! Instead, he expects it to be either a User or nil. But that's perfectly fine, because a User is truthy and nil is falsy, so they still can be used in a Boolean expression.
The basic intention is that the author wants to prevent a NoMethodError exception being raised, if he tries to call #record on nil.
An alternative way of expressing this would be
id = current_user.record.id unless current_user.nil?
If you want all the gory details, check out Section 11.1 (page 36) of the Draft ISO Ruby Specification or the excutable specifications of the RubySpec project. (Here's the one for &&.)
I wrote a pure Ruby implementation of Ruby's Boolean operators and conditional expressions once for fun. The meat of the implementations is these two mixins.
The logical and is short circuiting. That means that if the construct is X && Y, and X is false then Y never gets checked because the whole thing is certainly going to be yield false.
That code is saying, essentially:
if (current_user is TRUE) {
id = current_user.record.id;
]
Here's some console output showing you get the second value if the first is true:
irb(main):005:0> true && 9
=> 9
and nil if the first is nil:
irb(main):008:0> nil && 9
=> nil

Resources