Hacker News new | past | comments | ask | show | jobs | submit login

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.




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.


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 =)


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.


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 =)


> 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.


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?


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.


More discussion about this idiom, this time discussing Ruby 1.9's #tap method:

http://blog.rubybestpractices.com/posts/gregory/011-tap-that...


Any insight as to why they chose to name it tap instead of returning? I much prefer returning.


The original use cae was where you have a method chain and you want to "tap into" one of the values, e.g.

    foo().bar().blitz()
becomes:

    foo().bar().tap { |b| puts b.inspect }.blitz()
It takes its inspiration from Unix's "tee."




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: