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

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 Gray II

···

On Nov 8, 2006, at 8: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:

Buckblog: 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

Trans wrote:
[about #returning and #tap]

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

  45426320.9070405@path.berkeley.edu

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.

···

On 11/8/06, Trans <transfire@gmail.com> 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:

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

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

Buckblog: 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

···

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

--
Eric Hodel - drbrain@segment7.net - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

James Edward Gray II wrote:

···

On Nov 8, 2006, at 8: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?
>
> 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.

Eric Hodel 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.)

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.

···

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

Eric Hodel wrote:
...

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

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

···

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

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

···

On 11/8/06, Trans <transfire@gmail.com> wrote:

James Edward Gray II wrote:
> On Nov 8, 2006, at 8: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?
> >
> > 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.

Eric Hodel 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.)

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.

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.

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

···

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

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

--
Eric Hodel - drbrain@segment7.net - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

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

···

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Eric Hodel wrote:
...

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

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

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

···

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

--
Eric Hodel - drbrain@segment7.net - http://blog.segment7.net
This implementation is HODEL-HASH-9600 compliant

http://trackmap.robotcoop.com

Joel VanderWerf wrote:

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

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

and quite easy to golf if line count matters that much

   def foo
     @foo ||= Foo.new.instance_eval{ self.bar = 'bar'; self }
   end

-a

···

On Fri, 17 Nov 2006, Eric Hodel wrote:

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

--
my religion is very simple. my religion is kindness. -- the dalai lama

Eric Hodel wrote:

···

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

Eric Hodel wrote:
...

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

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

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

But you have to type @foo _five_ times, instead of once. Oh, well. It's a matter of taste.

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

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

···

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

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

martin

···

On 11/16/06, Hal Fulton <hal9000@hypermetrics.com> wrote:

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?

def foo; @foo ||= Foo.new.instance_eval{ self.bar = 'bar'; self } end

*smirks*

···

On 11/16/06, ara.t.howard@noaa.gov <ara.t.howard@noaa.gov> wrote:

and quite easy to golf if line count matters that much

   def foo
     @foo ||= Foo.new.instance_eval{ self.bar = 'bar'; self }
   end

--
Lou.

ROFL

Coming full circle around the golf course... This last one above is what lead me to prefer #then (== #tap) in the first place:

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

Also, #then avoids the scoping nastiness of #instance_eval.

···

ara.t.howard@noaa.gov wrote:

On Fri, 17 Nov 2006, Eric Hodel wrote:

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

and quite easy to golf if line count matters that much

  def foo
    @foo ||= Foo.new.instance_eval{ self.bar = 'bar'; self }
  end

-a

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407