
Object#returning (Ruby's K Combinator) - raganwald
http://weblog.jamisbuck.org/2006/10/27/mining-activesupport-object-returning
======
rob_rasmussen
For a different perspective on Object#returning, (and Symbol#to_proc and
friends), see <http://wiki.merbivore.com/pages/it-is-a-bug-if>

merb is one of the best-written Ruby libraries I've seen, in large part
because they're focused on avoiding clever code.

~~~
raganwald
I agree that it is a bug to use Symbol#to_proc or Object#returning in merb,
however I suggest that neither of these things are "clever."

Instead, I note that neither of these things are part of the standard library
today. Which means, you must open the Object or Symbol classes to implement
them. Nothing wrong with that in your code, but when you do so in a framework
like merb (or Rails!), everyone using your framework gets your little patches
in their namespace as well.

My feeling is that with the way Ruby's global class namespace works today,
opening a core class has much more serious consequences when you are writing a
framework, gem, or plug-in then when you are writing code that does not have
"downstream clients."

~~~
zenspider
Well, that's partially false. #to_proc is in 1.9.

I also completely and totally disagree that they're not clever. There is
nothing _not_ clever about #returning. It is second only to using inject
because you're too lazy to assign to a variable first. Nevermind that every
railz0r that does that ignores the fact that they've now assigned N times
instead of once.

Clever code, in my mind, is a form of hidden cost. It seems to be what I get
paid to deal with (read: remove) the most.

~~~
raganwald
See how our experiences differ? Just the other day I was fixing a bug caused
by someone writing:

    
    
      def squidget(options = {})
        squid = { :foo => :bar, ... }.merge(options)
        ...
        squid[:bash] = :blitz
      end
    

The method was returning :blitz instead of the hash that the method was
constructing. I changed it to a returning statement and to my eye it looks
much more clear what is going on.

Of course, you could add a "return squid" at the end, or just plain "squid,"
but somehow that seems less clear, since when you start manufacturing the
squid, it isn't obvious what you are doing until you reach the end of the
method. Witha returning statement, you know right away.

All in all, I feel good about all constructions in Ruby that use blocks to
wrap around the stuff they are doing, like

    
    
      Foo.transaction do
        ... 
      end
    

But you're younger than I am, so your brain is probably sharper. Maybe you
find it easier to just work directly with imperitive-style code. Many people I
know prefer it that way. I know I like to simulate Scheme as much as possible,
and use expressions instead of assigning local variables as much as possible.
It could be laziness on my part.

~~~
zenspider
assignment evaluation to RHS catches everyone once in a while. I'd have gone
with the plain `squid` at the end. Maybe even with a `return` if I was feeling
chatty. (It took me a long while to get over my anti-return-for-speed-reasons
bias... I'm still working on it sometimes.)

Besides, I'm not that much younger than you. :P

I think it is mostly that you went the lispy route while I took the smalltalk
route.

ETA:

actually... I'll go one step further...

`returning` violates "Do the Simplest Thing That Could Possibly Work" flat out
without giving you anything in return.

~~~
raganwald
"`returning` violates "Do the Simplest Thing That Could Possibly Work" flat
out without giving you anything in return."

We agree on the maxim while disagreeing with how to apply it. For me,
"returning" is simpler because it seems to involve fewer moving parts: you
don't have to remember to write 'squid' at the end and you get a local
variable that is scoped only to the block where it is needed.

To you, it is a gross and needlessly complicated way to write begin; squid =
...; squid; end. I can see how you would feel that way without feeling that
way myself.

I'm curious about the aversion to Symbol#to_proc. If you see [...].map(&:name)
and think of it as an abbreviation for { |element| element.name }, there isn't
much to like.

But coming from Smalltalk, does your brain ever click over and make you think
of [...].map(&:name) as meaning "map the message :name over this array"?

I ask because when I think of languages like Smalltalk and Ruby, I go along
with Alan kay and thenk of them as being message-oriented rather than object-
oriented. Symbol#to_proc seems to fit that somehow in my brain. I dunno how to
explain it any other way, it really feels less like an abbreviation to save
some characters and more like getting closer to what I am trying to say...

------
pius
It's (perhaps) worth noting that Object#returning is part of ActiveSupport,
not the Ruby Standard Library.

~~~
raganwald
True, and worth noting. Also of interest: Ruby 1.9 includes a different
implementation of the K Combinator, Object#tap. It's a method rather than a
pseudo-function, so instead of:

    
    
      returning (Fubar.new) do |f|
        ...
      end
    

Your write:

    
    
      Fubar.new.tap do |f|
        ...
      end
    

Shameless plug-whoring: The andand gem includes an enhanced Object#tap:
<http://andand.rubyforge.org>

------
ionfish
I had a couple of spare minutes so I did a JavaScript implementation.

<http://gist.github.com/7727>

------
Harkins
Also see <http://kcombinator.com>

------
eru
Side-effects are evil!

~~~
raganwald
Here's a use for the K Combinator that isn't Your Father's Imperative
Programming. I sometimes want an arbitrary, one-off object when testing or
prototyping things, perhaps in irb:

    
    
      foo = returning(Object.new) do |f|
        def f.bar
          ...
        end
        def f.bash
          ...
        end
      end

~~~
zenspider

      foo = returning(Object.new) do |f|
        def f.bar
          ...
        end
        def f.bash
          ...
        end
      end
    
      # vs
    
      foo = Object.new
      def foo.bar
        ...
      end
      def foo.bash
        ...
      end
    

1 line shorter, less indentation, more clear. What does returning get you
besides another message send and block activation? I have yet to see a good
use for it. (yes, I'm biased. calibrate accordingly)

~~~
raganwald
It really depends. If the definitions of foo.bar and foo.bash make sense
independantly of the assignment to foo, I prefer the second form as well. If
in my brain the whole thing is "atomic", I prefer the returning form or to
make a helper method so that they are composed into a logical chunk.

For the same reason, I write:

    
    
      foo = bar
      bash = blitz
    

When teh two statements are independant, and:

    
    
      foo, bar = bash, blitz
    

When they are deeply related and should not be broken up. Sometimes that is
hard to read and I will get gratuitous:

    
    
      begin
        foo = bar
        bash = blitz
      end
    

What can I say... that uses _more_ characters than needed. It isn't always
about saving electrons for me.

