#returning and #tap

Had use for this today: #returning is a convenience method you’ll find
in both Facets and ActiveSupport. Jamis’ blogged it the other day:

http://weblog.jamisbuck.org/2006/10/27/mining-activesupport-object-returning

Any one else think this is worthy of standard Ruby?

Also, a cool twist on the same concept is #tap. Check out the
MenTaLgeniuS:

http://moonbase.rydia.net/mental/blog/programming/eavesdropping-on-expressions.html

T.

On Nov 8, 2006, at 8:40 AM, Trans wrote:

MenTaLgeniuS:

http://moonbase.rydia.net/mental/blog/programming/eavesdropping-on-
expressions.html

One of the comments to the original article combines both methods
into a with() method that seems to be the best of both worlds.

James Edward G. II

Trans wrote:
[about #returning and #tap]

See also the »with construction« thread, especially as of:

[email protected]

Kalman

MenTaLguY’s use cases seem the more convincing of the two. Why would I
care about keeping an object anonymous when I’m leaving that scope
anyway? I guess in an inline lambda function it might be appropriate.
‘tap’ is what it’s likely to be used for most of the time. I’d call it
‘k’, personally, maybe with an alias to ‘tap’ or ‘tee’. I would like
to see it in standard Ruby.

Just realised that of course tap != k :stuck_out_tongue:

James Edward G. II wrote:

Also, a cool twist on the same concept is #tap. Check out the
MenTaLgeniuS:

http://moonbase.rydia.net/mental/blog/programming/eavesdropping-on-
expressions.html

One of the comments to the original article combines both methods
into a with() method that seems to be the best of both worlds.

Oh yea! I remember #with from way back, but then I don’t recall anyone
suggesting it return the object. Cool.

One thing though, while it covers #tap just fine, it doesn’t read the
same as #returning.

T.

On Nov 8, 2006, at 6:40 AM, Trans wrote:

Had use for this today: #returning is a convenience method you’ll find
in both Facets and ActiveSupport. Jamis’ blogged it the other day:

http://weblog.jamisbuck.org/2006/10/27/mining-activesupport-object-
returning

Any one else think this is worthy of standard Ruby?

From the blog post:

The latter is no shorter than the former, but it reads more
elegantly. It feels more “Rubyish”. And there are times that it
can save you a few lines of code, if that’s important. (Just scan
the Rails source code for more examples.)

So… it usually doesn’t save any lines, it adds typing, it hides the
object you’re returning in the middle of a statement and it is
significantly more expensive to execute[1]. (Oh, but maybe, in some
cases, it might save you one or two lines of code.)

No thanks.

I don’t think that makes it more rubyish. Every time I’ve
encountered #returning in Rails I’ve found it decreased the
readability of the code and uselessly increased the complexity.
(Wait, now what does this return? oh, yeah, way up there.)

1:

Rehearsal ---------------------------------------------
empty 0.290000 0.000000 0.290000 ( 0.391447)
returning 5.120000 0.050000 5.170000 ( 5.467861)
regular 2.660000 0.020000 2.680000 ( 2.900946)
------------------------------------ total: 8.140000sec

             user     system      total        real

empty 0.300000 0.000000 0.300000 ( 0.316623)
returning 5.160000 0.050000 5.210000 ( 5.815804)
regular 2.650000 0.020000 2.670000 ( 2.824744)

require ‘benchmark’

def returning(value)
yield(value)
value
end

N = 1_000_000

Benchmark.bmbm do |bm|
bm.report ‘empty’ do
N.times do end
end

bm.report ‘returning’ do
N.times do returning(Object.new) do |o| o.nil? end end
end

bm.report ‘regular’ do
N.times do o = Object.new; o.nil?; o end
end

end


Eric H. - [email protected] - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

On Nov 15, 2006, at 2:50 PM, Trans wrote:

cases, it might save you one or two lines of code.)

Er… that seems a backwards and inconsitant interpretation. How
can it
add typing if can save a line or two of code?

Most of the time it adds code. Look at the two examples on the blog
post. In the returning case I add “returning do || end” in the
simple case I have an extra “=”.

The example shows in the blog post shows returning saving exactly 0
lines of code. It claims that in some cases it saves lines, but
doesn’t give any examples, so it is probably a very rare statement.

Moreover it is optional usage, so use it when it saves you the
lines and not otherwise, or if it simply adds to the readility, and
not otherwise.

If it commonly saved lines then I’d expect the blog post would have
used such an example. I doubt that it commonly saves lines (the blog
post implies it usually does nothing to the line count).

As for “hides the object you’re returning in the middle of a
statement”, how’s that? The object is stated at the very beginning.

In most every other place in ruby the last line of a code grouping
construct is the return value. This is the way I’ve been reading my
Ruby for years. With #returning the return value is buried in the
middle of the line between “returning” and “do”.

It’s very readible. It says: here is the object we will return
after doing the following things to it.

That’s extra state I have to keep in my brain to keep the code straight.

Traditional code doesn’t require me to hold extra state in my head
because its linear. Linear is simpler and simpler is more readable.

Without it you have no idea what the goal is --return statements
could be deeping embedded inside the rest of the code.

This statement is orthogonal to the use of #returning. You may throw
in extra returns anywhere you like regardless of the #returning block.

Now, I grant you the speed issue sucks --and if that’s important,
again
you have the option of not using it. But also, if it were built in
perhaps it could be optimized (?)

Its simpler to just not have it at all. #returning gives no great
benefit and has many downsides.

find it helps.
#returning isn’t going to add any structure since it doesn’t really
do anything. You’re really just replacing ‘var’ with ‘end’ and
adding a bunch of whitespace.

Besides that the ‘tap’ functionality can be very hepful in it’s own
right.

So what? I didn’t mention #tap in my email.


Eric H. - [email protected] - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

Eric H. wrote:

return? oh, yeah, way up there.)
This variant saves typing and IMO is more idiomatically ruby:

class Object
def then
yield(self)
self
end
end

def foo
@foo ||= Foo.new.then do |f|
f.bar = “bar”
end
end

Otherwise you have to do this:

def foo
unless @foo
@foo = Foo.new
@foo.bar = “bar”
end
@foo
end

Eric H. wrote:

From the blog post:

The latter is no shorter than the former, but it reads more
elegantly. It feels more “Rubyish”. And there are times that it
can save you a few lines of code, if that’s important. (Just scan
the Rails source code for more examples.)

So… it usually doesn’t save any lines, it adds typing, it hides the
object you’re returning in the middle of a statement and it is
significantly more expensive to execute[1]. (Oh, but maybe, in some
cases, it might save you one or two lines of code.)

Er… that seems a backwards and inconsitant interpretation. How can it
add typing if can save a line or two of code? Moreover it is optional
usage, so use it when it saves you the lines and not otherwise, or if
it simply adds to the readility, and not otherwise. As for “hides the
object you’re returning in the middle of a statement”, how’s that? The
object is stated at the very beginning. It’s very readible. It says:
here is the object we will return after doing the following things to
it. Without it you have no idea what the goal is --return statements
could be deeping embedded inside the rest of the code.

Now, I grant you the speed issue sucks --and if that’s important, again
you have the option of not using it. But also, if it were built in
perhaps it could be optimized (?)

No thanks.

I don’t think that makes it more rubyish. Every time I’ve
encountered #returning in Rails I’ve found it decreased the
readability of the code and uselessly increased the complexity.
(Wait, now what does this return? oh, yeah, way up there.)

Well, a def can easily get “mucky”. #returning can help provide some
structural constraint. Most the time it isn’t needed, but on occasion I
find it helps.

Besides that the ‘tap’ functionality can be very hepful in it’s own
right.

T.

Joel VanderWerf wrote:

This variant saves typing and IMO is more idiomatically ruby:

class Object
def then
yield(self)
self
end
end

Oops, sorry. I didn’t realize that #tap is the same as #then.

I can’t quite see why “tap” is a good name for that, though…

Joel VanderWerf wrote:

Oops, sorry. I didn’t realize that #tap is the same as #then.

I can’t quite see why “tap” is a good name for that, though…

I suppose it’s as in “tap a keg.” :slight_smile:
In other words, an analogy for the Unix “tee”
utility, which is named for a T-shaped (real-life) pipe…

Or am I wrong?

Hal

Eric H. wrote:

Most of the time it adds code. Look at the two examples on the blog
post. In the returning case I add “returning do || end” in the
simple case I have an extra “=”.

The example shows in the blog post shows returning saving exactly 0
lines of code. It claims that in some cases it saves lines, but
doesn’t give any examples, so it is probably a very rare statement.

If it commonly saved lines then I’d expect the blog post would have
used such an example. I doubt that it commonly saves lines (the blog
post implies it usually does nothing to the line count).

In most every other place in ruby the last line of a code grouping
construct is the return value. This is the way I’ve been reading my
Ruby for years. With #returning the return value is buried in the
middle of the line between “returning” and “do”.

That’s extra state I have to keep in my brain to keep the code straight.

Traditional code doesn’t require me to hold extra state in my head
because its linear. Linear is simpler and simpler is more readable.

This statement is orthogonal to the use of #returning. You may throw
in extra returns anywhere you like regardless of the #returning block.

Its simpler to just not have it at all. #returning gives no great
benefit and has many downsides.

#returning isn’t going to add any structure since it doesn’t really
do anything. You’re really just replacing ‘var’ with ‘end’ and
adding a bunch of whitespace.

Well, it does add structure, otherwise there would be not be any point
whatsoever. You may or may not like that structure and certainly you
make some fair points. But if I can ask you a question: do you use this

f = File.open(‘foofile’)
…do stuff with f…
f.close

Or do you use

File.open(‘foofile’) do |f|
…do stuff with f…
end

B/c all of your above arguments appear equally applicable here. The
block form of File.open provides a similar kind of structure. And while
you might say that the block form of File.open ensures the file is
closed, which gives it it’s value, I say there in lies a complementary
point. A properly implemented #returning would ensure that only the
specified object is returned, and nothing else --so internal returns
would not work, because that is the structure it provides.

Besides that the ‘tap’ functionality can be very helpful in it’s own
right.

So what? I didn’t mention #tap in my email.

B/c even if we were to agree that #returning has little value in the
context presented, both it and #tap have have the same exact
definition. Hence it has use in other contexts as well. Since
#returning has greater semantic recognition, why have #tap at all when
#returning would do as well?

BTW, is seems a bit arrogant to presume yourself the hallmark of
relevancy. I brought it up b/c I saw it as relevant. I’m sorry I did
not elaborate on the relationship. I mistakenly assumed it was plain.

T.

Hal F. wrote:

Joel VanderWerf wrote:

I can’t quite see why “tap” is a good name for that, though…

I suppose it’s as in “tap a keg.” :slight_smile:
In other words, an analogy for the Unix “tee”
utility, which is named for a T-shaped (real-life) pipe…

A tee branches. Does a keg tap branch?

Hum, maybe it does. I skipped all those I Tappa Keg parties.

I think where returning really makes a difference is with local
variables. If you have some code where you want to initialize a local
variable in a block and then use it afterward your up the creek.

def foo(a)
  a.each do |x|
    (b ||= []) << x
  end
  b # => oops
end

a = [1,2,3]
p foo(a)

What you need to do, of course, is just initialize before the block:

def foo(a)
  b = []
  a.each do |x|
    b << x
  end
  b
end

Ugly. Sorry, it just is. It is much more readable to use returning.

def foo(a)
  returning [] do |b|
    a.each do |x|
      b << x
    end
  end
end

On another note, I don’t buy the argument that this is a bad practice
because the you no longer look for the last value to see what is
returned. That’s exactly what you do. The last element in this
function is the ‘end’ of the returning block. What does returning
return? I think its pretty obvious personally.

On 11/16/06, Hal F. [email protected] wrote:

Or am I wrong?

More likely tap as in “tap a phone line”, i.e. both siphon off a value
and let it be passed on.

martin

On Nov 16, 2006, at 10:56 AM, Ryan D. wrote:

def foo(a)
a.map { |x| x }
end

More readable, faster, better…

Which is just a longer way to say:

def foo(a)
a.to_a
end

James Edward G. II

On Nov 16, 2006, at 10:46 AM, Louis J Scoras wrote:

Ugly. Sorry, it just is. It is much more readable to use returning.

def foo(a)
returning [] do |b|
a.each do |x|
b << x
end
end
end

I realize this is a contrived example on your part, but you did
choose it and were trying to make a relevant point. That said, I have
yet to see an example of returning used in a non-contrived way.

def foo(a)
a.map { |x| x }
end

More readable, faster, better… once again returning is used in a
completely useless way…

On 11/16/06, Ryan D. [email protected] wrote:

I realize this is a contrived example on your part, but you did
choose it and were trying to make a relevant point. That said, I have
yet to see an example of returning used in a non-contrived way.

[snip]

once again returning is used in a completely useless way…

No. You’re absolutely right that this was a useless, contrived
example; however, I think the point still comes across. Sometimes you
need to initialize a local variable before you use it a block. In
that case I still contend that ‘returning’ is more readable than the
initialize/mutate/return pattern.

This is a pattern that should be extracted; basically it’s inject w/o
the iteration component.

On Nov 15, 2006, at 5:40 PM, Joel VanderWerf wrote:

(Wait, now what does this return? oh, yeah, way up there.)
def foo
@foo ||= Foo.new.then do |f|
f.bar = “bar”
end
end

$ wc
[…]
5 12 67

Otherwise you have to do this:

I would write it:

def foo
return @foo if @foo
@foo = Foo.new
@foo.bar = ‘bar’
@foo
end

$ wc

6 14 77

Ten characters and one line more typing, but less punctuation. (And
those ten extra characters will be mostly be handled by my tab key.)


Eric H. - [email protected] - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com