Are return statements bad in Ruby? - ruby

The return keyword is optional in ruby so for functions with only one exit point, "return result" can be safely replaced with simply "result".
Is there any Ruby-specific guidelines to when to do this?
I tend to avoid the return keyword as much as possible due to their unruly behavior in procs.

"return" in ruby is only used if you are trying to return more than one value. e.g.
return val1, val2
or if it makes sense to return earlier from a function e.g.
#check if needed param is set
return if !param
#some operations which need param
which is easier than messing your code up with cascaded if-statements.
Conclusion: Use return every time it simplifies your code or it makes it easier to understand.

Related

Ruby evaluates the default value in fetch even when key is found

h = {a: "foo"}
h.fetch(:a, h.fetch(:b))
yields key not found: :b
It seems strange that Ruby evaluates the default value even when the key is found? Is there a way around this?
Edit: Apparently this behavior falls under the paradigm of lazy vs eager evaluation. Nearly all imperative languages use eager evaluation, while many functional languages use lazy evaluation. However some languages, such as Python (which was before last week the only language I knew), have lazy evaluation capabilities for some operations.
It seems strange that Ruby evaluates the default value even when the key is found? Is there a way around this?
The overwhelming majority of mainstream programming languages is strict, i.e. arguments are fully evaluated before being passed. The only exception is Haskell, and calling it mainstream is a bit of a stretch.
So, no, it is not really "strange", it is how (almost) every language works, and it is also how every single other method in Ruby works. Every method in Ruby always fully evaluates all its arguments. That is, why, for example defined? and alias cannot be methods but must be builtin language constructs.
However, there is a way to delay evaluation, so to speak, using blocks: the content of a block is only evaluated each time it is called. Thankfully, Hash#fetch does take a block, so you can just use
h.fetch(:a) { h.fetch(:b) }
If you want the computation to only run if the key is not found, you can use the alternate form of fetch which accepts a block:
h.fetch(a) { h.fetch b }
I didn't actually know this was the case but I had a hunch and tried it and it worked. The reason I thought to try this was that something similar can be done in other methods such as gsub, i.e.
"123".gsub(/[0-9]/) { |i| i.to_i + 1 } == "234"
You could use the || operator instead, since it's lazy evaluated by design.
For example the following code where Nope is not defined does not throw an error.
{ a: "foo" }[:a] || Nope
However the fetch version will throw an error.
{ a: "foo" }.fetch(:a, Nope)
Personally I prefer how fetch is designed because it wont hide a bug in the default value.
However, in cases where I would rather not evaluate a default statement, then I would definitely reach for the || operator before doing something in a block or a lambda/proc.

What's the rationale for the block argument?

I'm just learning about Ruby, and am having trouble seeing the point of the so-called "block argument" (which can be appended to method invocations).
AFAICT, the "block argument" works like any run-of-the-mill callback argument in other programming languages (or in Ruby itself, for that matter), but are more limited in that one can attach at most one "block argument" to a method invocation, while there's no upper limit on the number of callback arguments a method/function can be designed to accept.
(In case clarification is needed, by "callback" all I mean is a function F that another function G receives (as one of its arguments) and in turn calls.)
I figure that there must be something that one can do with a block argument that can't be done just as easily with a callback (otherwise, it's hard to justify supporting a special syntax for block arguments), but I can't figure out what this "something" could be.
My question is just that:
What can be done with a "block argument" that couldn't be done with regular callback?
EDIT: An earlier comment (now deleted) said that block arguments are better described as "closures" than as "callbacks". In my book, closures are a special case of callbacks. One can, if one wants, replace "callback" with "closure" in my post. The post's question still remains (unless, of course, "block arguments" were the only way to create closures in Ruby, but if this were the case, it in itself would raise more questions than it answers).
I figure that there must be something that one can do with a block argument that can't be done just as easily with a callback (otherwise,
Yes. Blocks are a sort of "syntactic sugar", but they are also functionally quite different from "callback function" in a language like JavaScript.
For one thing, the return keyword functions very differently than it does in functions and methods both in Ruby and other languages.
Inside a block, return jumps out of the containing method, while in a method return jumps out of (obviously) the method.
This is important for the following case:
def find_by_email(users, search_email)
users.each do |user|
# return all the way out of find_by_email
return user if user.email == search_email
end
nil
end
Here, we're using each to iterate over a collection. If some condition is me inside the block, the user is returned all the way out of the containing method.
This doesn't work with a function. Compare the "identical" JavaScript code, which doesn't work as intended:
function findUserByEmail(users, searchEmail) {
users.forEach(function (user) {
if (user.email == searchEmail) {
// return out of `forEach`
return user;
}
});
// broken
}
I don't think anything can be done with blocks that can't be done with passing functions (such as in javascript) .
I think that the creators of ruby figured that in 95% of cases, you want to pass only one callback to a function, not more. So they created very nice syntax for that:
Post.all.map { |post| puts post.title }
Compare to javascript
$(document).on('click', function() {
DO SOMETHING
}
To sum: I think that passing blocks is a syntax sugar in ruby, comparable to passing functions in js but nicer looking. In the majority of cases you will want to pass one block (or callback) anyway.

Do all methods have to return a meaningful value?

Here's a snippet of code from the pickaxe book:
def count_frequency(word_list) counts = Hash.new(0)
for word in word_list
counts[word] += 1
end
counts
end
The counts at the end sets the return value of the method. The value returned is the value of the last calculation.
However, are there not cases where we don't care what the return value of a method is? For example, I have a pair of nested each loops that draw a checkerboard to console. The values of the calculations are fairly meaningless outside the method. I just want a checkerboard drawn.
Is it bad to leave the return value up to circumstance, or should I always be trying to explicitly design methods that return meaningful values?
You don't have to care about the return value if that method is not used as such with a certain expected value. Nothing to worry about.
But for your counts example, returning that value is the whole point of the method. If the method didn't return that value, then it is meaningless, and you definitely need that counts at the end.
There are some cases when the return value is not the main purpose of the method but you still want to return a certain value. One such case is when the method is intended to be used in a jQuery-style method chain like this:
some_object.do_this(args).do_that(args).then_do_this
In such case, it is important that you return the receiver. This happens in certain libraries or frameworks, but unless you specifically intent it to be used that way, you don't necessarily have to do it that way.
No, the return value is not necessary when the method isn't supposed to return a meaningful value, just like most other programming languages.
In fact, one of the most common methods, puts, returns nil.
#puts "hello"
hello
=> nil
No.
In Ruby, every expression returns a value, even if it is just nil. Not just methods; every line you write. In the case of methods, the value returned is the last value evaluated before it exits. The meaning of that value is up to you. If you document that the method has no return value, then even though it does return a value it is undefined; not part of the API and the caller would be wise not to make use of it.
For example, even nil can have proper meaning if you document it; it is often used to signal that a resource could not be found. However, if a method's sole purpose is to perform a side effect like writing to a file, it will probably something that has no real meaning; puts returns nil.
Theoretically, if you document clearly that the return value is meaningless, then you could just incidentally return whatever the last expression in the method happens to evaluate to.
Practically, however, nobody reads documentation, so, if your method does return something, then people will come to depend on it. Also, depending on what exactly it is that you are "accidentally" returning, you might leak private internal implementation details of your method or you might even break encapsulation of your object by e.g. returning the value of a private instance variable.
Take the defined? unary prefix operator, for example. It is specified as returning either a trueish or a falseish value. However, on MRI, it does not just return any trueish value, it actually returns a String describing the kind of expression that is asked about (e.g. 'local-variable', 'method', etc.) And people have become so dependent on this return value that all other Ruby implementations just have to mimic it, even though it is nowhere documented. Now, it turns out that for MRI this information is trivially available, but for JRuby it is not, and keeping this information around incurs a performance penalty.
The E programming language is a purely expression-based language like Ruby or Lisp. Everything is an expression, there are no statements. Everything returns a value. However, unlike those other languages, the implicit return value of a subroutine is not the value of the last expression evaluated inside the subroutine, it is nil. You must explicitly return a value if you want to return something meaningful. That is because the creator of E believes that it is too dangerous to accidentally return something you didn't want. (E is explicitly designed for security, safety, integrity and reliability.)

Does Ruby have a special storage for returning a value?

The following Ruby code
def a(b,c) b+c end
is the same as follows with Python
def a(b,c): return b+c
It looks like that ruby has the special storage(stack or something) that stores the final evaluation result and returns the value when a function is called.
If so, what's the name of the stack, and how can I get that stack?
If not, how does the Ruby code work without returning something?
It's not that magic, Ruby just returns the value returned by the operation that does at the end.
It's synctactic sugar that it's implemented just at parsing level: a statement that calculates something implicitly returns itself without any keyword..
to clarify it a little bit you can imagine both abstract syntax trees of the two snippets: they won't be different.
I don't think it's a stack. The final evaluation of the function is simply the return value, plain and simple. Just your everyday Ruby syntactic sugar.
I don't see any reason why a stack should be required to return a result. A simple pointer to a memory location would be sufficient. I'd guess that would usually be returned in a register, such as EAX.
You get the return value of a function by assigning the function's value to a variable (or doing something else with it). That's the way it was intended to be used, and the only way that works.
Not returning anything is really easy: The called function doesn't put anything into the return location (whatever it may be) and the caller ignores it.
Actually, return is special here, not the standard behavior. Consider:
def foo(ary)
ary.each do |e|
return true if e == 2
end
end
This code actually has more then one stack frame (at least the on for #foo, the one for Array#each and the one for the anonymous function passed to #each). What return does: it does a jump to the stack frame of the outermost lexical scope it is called in (the end of foo) and returns the given value. If you play a lot with anonymous functions, you will find that return is no allowed in all context, while just returning the last computed value is.
So I would recommend never to use return if you don't need it for precisely that reason: breaking and returning from a running iteration.

General programming - calling a non void method but not using value

This is general programming, but if it makes a difference, I'm using objective-c. Suppose there's a method that returns a value, and also performs some actions, but you don't care about the value it returns, only the stuff that it does. Would you just call the method as if it was void? Or place the result in a variable and then delete it or forget about it? State your opinion, what you would do if you had this situation.
A common example of this is printf, which returns an int... but you rarely see this:
int val = printf("Hello World");
Yeah just call the method as if it was void. You probably do it all the time without noticing it. The assignment operator '=' actually returns a value, but it's very rarely used.
It depends on the environment (the language, the tools, the coding standard, ...).
For example in C, it is perfectly possible to call a function without using its value. With some functions like printf, which returns an int, it is done all the time.
Sometimes not using a value will cause a warning, which is undesirable. Assigning the value to a variable and then not using it will just cause another warning about an unused variable. For this case the solution is to cast the result to void by prefixing the call with (void), e.g.
(void) my_function_returning_a_value_i_want_to_ignore().
There are two separate issues here, actually:
Should you care about returned value?
Should you assign it to a variable you're not going to use?
The answer to #2 is a resounding "NO" - unless, of course, you're working with a language where that would be illegal (early Turbo Pascal comes to mind). There's absolutely no point in defining a variable only to throw it away.
First part is not so easy. Generally, there is a reason value is returned - for idempotent functions the result is function's sole purpose; for non-idempotent it usually represents some sort of return code signifying whether operation was completed normally. There are exceptions, of course - like method chaining.
If this is common in .Net (for example), there's probably an issue with the code breaking CQS.
When I call a function that returns a value that I ignore, it's usually because I'm doing it in a test to verify behavior. Here's an example in C#:
[Fact]
public void StatService_should_call_StatValueRepository_for_GetPercentageValues()
{
var statValueRepository = new Mock<IStatValueRepository>();
new StatService(null, statValueRepository.Object).GetValuesOf<PercentageStatValue>();
statValueRepository.Verify(x => x.GetStatValues());
}
I don't really care about the return type, I just want to verify that a method was called on a fake object.
In C it is very common, but there are places where it is ok to do so and other places where it really isn't. Later versions of GCC have a function attribute so that you can get a warning when a function is used without checking the return value:
The warn_unused_result attribute causes a warning to be emitted if a caller of the function with this attribute does not use its return value. This is useful for functions where not checking the result is either a security problem or always a bug, such as realloc.
int fn () __attribute__ ((warn_unused_result));
int foo ()
{
if (fn () < 0) return -1;
fn ();
return 0;
}
results in warning on line 5.
Last time I used this there was no way of turning off the generated warning, which causes problems when you're compiling 3rd-party code you don't want to modify. Also, there is of course no way to check if the user actually does something sensible with the returned value.

Resources