

Rewriting Returning in Rails - raganwald
http://github.com/raganwald/homoiconic/blob/master/2009-08-29/returning.md#readme

======
codyrobbins
I personally find the #returning method very ugly. It's an abstraction that
seems completely unnecessary to me. Instead of assigning a variable and then
returning the value, two very fundamental mechanisms in the language that are
easily understood by any programmer (whether they know Ruby or not), you're
bypassing them and introducing this method whose purpose I don't feel is
immediately obvious.

It would be one thing if the pattern saved a lot of unnecessary code, but it
doesn't. The assignment of the local variable just becomes the block variable,
and you have an 'end' where the method-final return would be. Instead of a
simple assignment, you now have the method invocation and the arguably more
complicated block syntax.

I'll address the two particular motivations raised by the author specifically
because I don't agree with either of them. First, I don't think forgetting to
return the variable is a common bug. Anecdotally, I can't ever remember making
this mistake myself. Even if I were to, it would be immediately obvious what
the problem is. I'm open to the fact that other people perhaps make this
mistake, but I'd be surprised if they routinely do. Second, I don't feel like
it's obvious at all what the return value of the method is up-front, because
the method invocation is confusing if you don't know what it does. Even if you
do, it doesn't gain you anything you don't get by simply initializing a local
at the start of the method, especially if you call the local return_value or
something self-descriptive like that.

This kind of refactoring is the kind that I don't like — refactoring for the
sake of refactoring, and making the code less accessible (that is, more
complicated and harder to understand) for no discernible benefit.

~~~
raganwald
I'm not sure if you are arguing with me or with Rails. Rails includes the
#returning method. If you don't like using it you are entitled to your
opinion. I won't argue with you, because that is not what this post is really
about.

I encountered bugs like forgetting to return the intialized object from a
method as well as assigning to the parameter of a return invocation a number
of times when working with a large Rails code base. But if you have never
encountered it, you need never use #returning in any of its forms.

So really, I'm not arguing with you. Different people, different experiences,
different approaches to code. I like #returning, I like #let, I like a lot of
things that impose block structure on code. Others do things differently with
my blessing.

~~~
codyrobbins
Yeah, I know I don't have to use it. I just think the style it introduces is
more abstruse overall than the problem it's solving. To answer your question,
I'm mostly arguing with Rails, not you. Obviously, if it's useful to people
they'll use it and who am I to declare by fiat that something's not useful to
somebody else? But just because some level of personal preference is involved
doesn't mean we can't try to talk about something on the basis of its
objective merits.

But I'm often (usually?) wrong — I was just putting in my two cents for the
sake of discussion =)

~~~
raganwald
Well then, if you want to talk, I'd say this... (elided).

No, scratch that, instead I'll say this: I don't buy the argument that
#returning, or SymbolToProc, or any of the other myriad (and often irritating)
little idiomatic extensions to Ruby make code less complicated and more
difficult to read.

It's an old, old argument and tiresome to rehash, but ultimately it's a
mistake to make things easier to read for someone who doesn't know the idioms
at the expense of making things easier to read for somone who does know the
idioms.

If you feel the idiom doesn't add value, that's one thing. But I have trouble
with the idea that #returning is harder to read. I personally find it easier
to read because it is so obvious what is going on.

~~~
codyrobbins
Isn't it implied and understood that I can only speak for myself and from my
own perspective? I think my post was littered liberally enough with words like
'personally' and 'I feel' that it's understood I'm not trying to speak in
absolutes. So, would you rather I didn't raise any questions about the
relative merits of the code simply because there may be people who find it
useful? I'm certainly not arguing that no one will find it useful, I'm simply
saying that I don't like it and giving the reasons why I think so. If you
didn't want people to discuss the relative merits of the code, why did you
post it?

EDIT: Ah, you elided what the above is a rebuttal of, which is good because
that brings the discussion back to the actual code in question.

There are a ton of little idiomatic extensions to Ruby that are immensely
useful, SymbolToProc being a very good example. The presence of so many of
them is one of the great things about Rails. So, I'm not arguing against such
things as a whole, as you imply I am. I'm simply saying that #returning in
particular is one that I have problems with.

Nor am I saying that making things less readable for the uninitiated is a
sufficient motivation to bar use of such things. However, this particular
idiom gives you so little that I feel what you gain from it does not outweigh
the cost of introducing it. So, I do feel that the idiom doesn't add any
value, and for that reason there is a cost associated with its use.

It doesn't save you any code, and it's more complicated than the code it
replaces, which is why I am puzzled that you find it easier to understand. It
makes things wordier with a block invocation when a simple assignment will
suffice. Ostensibly, assignment is a much 'lower level' mechanism than
invoking a method with a block.

I readily admit, though, that if you find it easier to read then there's no
argument I can make, because it works for you. Similarly, though, I can state
that it is not easier to read for me. So, I guess we just have to agree to
disagree on the basis that our brains work differently =)

~~~
raganwald
> I think my post was littered liberally enough with words like 'personally'
> and 'I feel' that it's understood I'm not trying to speak in absolutes.

It was understood right up to the words "no discernable benefit" that closed
the original comment :-) But any ways, of course I expect lively discussion
about the post, just as you must expect responses to your comment.

So to get back to the actual subject of the #returning idiom... I think your
comments apply to a lot of Ruby idioms as distinguished from abstractions. For
example, is `customers.map(&:name)` a win over `customers.map { |c| c.name }`?
Is `customers.first.try(&:name)` a win over `customers.first &&
customers.first.name`? Brevity alone is not enough reason to prefer these
idioms, IMO. You have to buy that they express the intention more clearly,
making them more readable, not less readable in your eyes.

Some people just don't see such idioms as making the code more precise, more
communicative. If you're in that camp with respect to #returning, you are not
alone by a long shot.

~~~
codyrobbins
OK, I think we're on the same page regarding our meta-discussion =)

Yes, I absolutely find

    
    
      customers.map(&:name)
    

a win over

    
    
      customers.map { |c| c.name }
    

My reasoning is that the former is less code overall, is fundamentally
'simpler' (passing a parameter to a method rather than calling with a block),
and the code it replaces has redundancy (the block parameter is there only to
be immediately referenced for the sole purpose of getting at one of the
object's attributes). With #try, there's similarly less code overall and it
removes redundancy.

I agree that brevity alone is not enough to prefer one idiom over another.
Expressiveness is a big part. I like these idioms, so I'm actually in the camp
that they _do_ make the code more precise and communicative.

In my book, though, #returning is simply an exception. A simple assignment and
return are already so fundamentally expressive on their own, that — to me —
replacing them with a method invocation and block doesn't get you more
expressiveness, and instead it actually makes things less readable.

To me, it would be like writing an abstraction layer to replace the use of
variables in the language, where you have to invoke a special-purpose lookup
table class to set and retrieve values. Why would you prefer

    
    
      Variable.set(:foo, 'bar')
      puts(Variable.get(:foo))
    

over

    
    
      foo = 'bar'
      puts(foo)
    

Why not just use variables?

~~~
raganwald
Funny you mention that. If you had your own implementation of variables, you
could probably override the behaviour of parameters in the #returning method
to get the behavior in the OP without rewriting code.

Naturally the syntax looks a little ugly to the ALGOL-shaped eye, but imagine
such a thing written _into the language_. It would be trivial to permit the
ALOGOL-like syntax in the code but also allow you to override the #get and
#set methods when you want to.

IIRC, this is exactly what Generalized Variables are in Common Lisp. Variables
where you override the meaning of setting and getting their value.

Ruby sorta kinda allows this in a very limited case. While you cannot override
the meaning of:

    
    
        foo = "foo"
    

You _can_ create setter method such as:

    
    
        class MyStack
          
          # ...
    
          def top
            @array[-1]
          end
    
          def top=(value)
            @array[-1] = value
          end
    
        end
    

Thus, stack.top and stack.top = "foo" can do whatever you want.

------
btakita
It is very difficult to read this method.

The more standard way goes from top to bottom. The lambda method requires the
reader to go to the bottom of the statement, then to the top and downward. It
requires the writer to remember the idiom and it's a barrier to newer
developers.

I also don't see the win in doing this either. Sure, somebody can forget to
set the return value, but you can also screw up with the other idiom. That
part seems like a wash to me.

* edit - Grammatical corrections and reformatting.

~~~
raganwald
I should explain a little more. You never actually _see_ the lambda method,
the RewriteRails plugin works a little like Lisp's macros. You write:

    
    
        returning [1] do |numbers|
          numbers << 2
          numbers += [3]
        end
    

And that's all you see in your source code. RewriteRails rewrites that into:

    
    
        lambda do |numbers|
          numbers << 2
          numbers += [3]
          numbers
        end.call([1])
    

And that's what the ruby interpreter sees. But you need never look at the
"ugly" rewritten version, just what you wrote.

~~~
btakita
I can see that as an improvement. Thanks for the follow up.

