Tue
4
Apr '06
|
|
I like Ruby, I really do. But there is one thing I just don’t get. I seems to be good Ruby style to use as much implicit returns as possible. Why?
If you take a look at the code from this very interesting article
class DataRecord
[...]
end
data.close
array
end
klass
end
end
Why not use a additional return here:
class DataRecord
[...]
end
data.close
array
end
return klass
end
end
Leaving out the return saves you 7 characters but I think at the cost of clarity. But I’m wondering if I’m missing something here…
Addendum
I learn a lot and like Emmet said:
The really big win you get from implicit return isn’t in functions like the one you gave as an example, it’s in functions like this…
Thanks everybody for the great responses.
Yes, you are missing something.
It is an attempt to remedy the problem mentioned here, in point #6
http://www.paulgraham.com/diff.html
“6. Programs composed of expressions. Lisp programs are trees of expressions, each of which returns a value. (In some Lisps expressions can return multiple values.) This is in contrast to Fortran and most succeeding languages, which distinguish between expressions and statements.
It was natural to have this distinction in Fortran because (not surprisingly in a language where the input format was punched cards) the language was line-oriented. You could not nest statements. And so while you needed expressions for math to work, there was no point in making anything else return a value, because there could not be anything waiting for it.
This limitation went away with the arrival of block-structured languages, but by then it was too late. The distinction between expressions and statements was entrenched. It spread from Fortran into Algol and thence to both their descendants.”
You clearly have grown up in a Fortran-derived world. The guy who created Ruby actually knows other languages, and must think they are somehow superior for not having this arbitrary limitation.
When a language is made entirely of expressions, you can compose expressions however you want. You can say either (using Arc syntax)
(if foo (= x 1) (= x 2))
or
(= x (if foo 1 2))
I understand, why it’s a neat thing if every operation returns something, but I still find it hard to read such code. I guess you are right, this is probably due to the lack of functional programming in my past.
A subtle point is that implicit and explicit return can have different semantics. In the following example:
def pig_out(bushel)
bushel.map do |fruit|
eat(fruit)
if sick? then
return “this #{fruit} is bad!”
end
”this #{fruit} is delicious!
end
end
If all the fruit are good, then the result of #pig_out will be a list of strings like “this … is delicious!”. If there’s a bad apple in the bushel, however, the result of #pig_out will be a single string “this apple is bad!”. When “return” is used, it tells Ruby to abandon whatever it was doing and immediately return from the containing method. The semantics of return are just like those of the “throw” kernel method.
So it may be that the reason a lot of Ruby code eschews “return” is because, since it is a more “drastic” operation, it is reserved for the special cases when it is genuinely required.
The really big win you get from implicit return isn’t in functions like the one you gave as an example, it’s in functions like this:
def collect_times_two(array)
array.collect{ |x| x*2 }
end
With required returns, this elegant looking piece of code turns into:
def collect_times_two(array)
return array.collect{ |x| return x*2 }
end
which is definitely less readable.
The “programs are composed of expressions” view can also increase readability. Here are a couple examples:
def fact(n)
if n ==0
1
else n * fact(n-1)
end
end
Also I find this:
if cond
temp = foo
else temp = bar
end
temp.some_complicated_expr
less readable than:
(if cond
foo
else bar
end).some_complicated_expr
Ignoring these wanna-be lispers…
One thing to note is that the implicit return is (slightly-but-measurably) faster than the explicit return.