#returning and #tap

Discussion in 'Ruby' started by Trans, Nov 8, 2006.

  1. Trans

    Trans Guest

    Trans, Nov 8, 2006
    #1
    1. Advertising

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

    James Edward Gray II
    James Edward Gray II, Nov 8, 2006
    #2
    1. Advertising

  3. Trans

    Kalman Noel Guest

    Trans wrote:
    [about #returning and #tap]

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



    Kalman
    Kalman Noel, Nov 8, 2006
    #3
  4. Trans

    spooq Guest

    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 <> 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
    >
    > T.
    >
    >
    >
    spooq, Nov 8, 2006
    #4
  5. Trans

    Trans Guest

    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.
    Trans, Nov 8, 2006
    #5
  6. Trans

    spooq Guest

    Just realised that of course tap != k :p


    On 11/8/06, Trans <> 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.
    >
    >
    >
    spooq, Nov 8, 2006
    #6
  7. Trans

    Eric Hodel Guest

    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-=20
    > returning
    >
    > Any one else think this is worthy of standard Ruby?


    =46rom the blog post:

    >> The latter is no shorter than the former, but it reads more =20
    >> elegantly. It feels more =93Rubyish=94. And there are times that it =20=


    >> can save you a few lines of code, if that=92s important. (Just scan =20=


    >> the Rails source code for more examples.)


    So... it usually doesn't save any lines, it adds typing, it hides the =20=

    object you're returning in the middle of a statement and it is =20
    significantly more expensive to execute[1]. (Oh, but maybe, in some =20
    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 =20
    encountered #returning in Rails I've found it decreased the =20
    readability of the code and uselessly increased the complexity. =20
    (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 =3D 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 =3D Object.new; o.nil?; o end
    end

    end

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

    http://trackmap.robotcoop.com
    Eric Hodel, Nov 15, 2006
    #7
  8. Trans

    Trans Guest

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


    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.
    Trans, Nov 15, 2006
    #8
  9. Trans

    Eric Hodel Guest

    On Nov 15, 2006, at 2:50 PM, Trans wrote:
    > Eric Hodel wrote:
    >> 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.)

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

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

    http://trackmap.robotcoop.com
    Eric Hodel, Nov 15, 2006
    #9
  10. 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
    Joel VanderWerf, Nov 16, 2006
    #10
  11. 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
    Joel VanderWerf, Nov 16, 2006
    #11
  12. Trans

    Hal Fulton Guest

    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." :)
    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
    Hal Fulton, Nov 16, 2006
    #12
  13. Trans

    Trans Guest

    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.
    Trans, Nov 16, 2006
    #13
  14. 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." :)
    > 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
    Joel VanderWerf, Nov 16, 2006
    #14
  15. On 11/16/06, Hal Fulton <> 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." :)
    > In other words, an analogy for the Unix "tee"
    > utility, which is named for a T-shaped (real-life) pipe...
    >
    > 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
    Martin DeMello, Nov 16, 2006
    #15
  16. 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.



    --
    Lou.
    Louis J Scoras, Nov 16, 2006
    #16
  17. Trans

    Ryan Davis Guest

    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...
    Ryan Davis, Nov 16, 2006
    #17
  18. On Nov 16, 2006, at 10:56 AM, Ryan Davis 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 Gray II
    James Edward Gray II, Nov 16, 2006
    #18
  19. On 11/16/06, Ryan Davis <> 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.


    --
    Lou.
    Louis J Scoras, Nov 16, 2006
    #19
  20. Trans

    Eric Hodel Guest

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

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

    http://trackmap.robotcoop.com
    Eric Hodel, Nov 16, 2006
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Patrick

    Number of TAP nyquist filter

    Patrick, Jun 11, 2004, in forum: VHDL
    Replies:
    2
    Views:
    919
    Ray Andraka
    Jun 14, 2004
  2. Andrew
    Replies:
    0
    Views:
    392
    Andrew
    May 23, 2008
  3. Marty Ryba
    Replies:
    6
    Views:
    597
    Marty Ryba
    Aug 19, 2008
  4. Replies:
    35
    Views:
    285
    Robert Klemme
    Nov 17, 2007
  5. Matej Cepl

    Python and TAP

    Matej Cepl, Feb 6, 2012, in forum: Python
    Replies:
    6
    Views:
    1,211
    Matej Cepl
    Feb 7, 2012
Loading...

Share This Page