#returning and #tap

A

ara.t.howard

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
 
L

Louis J Scoras

and quite easy to golf if line count matters that much

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

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

*smirks*
 
J

Joel VanderWerf

Eric said:
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.
 
J

Joel VanderWerf

and quite easy to golf if line count matters that much

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

-a

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

dblack

Hi --

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.

I'm not getting the semantics of "then". Do you mean "then" as in, "I
took off my coat and then sat down", as opposed to then in if/then?


David

--
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
 
J

Joel VanderWerf

Hi --



I'm not getting the semantics of "then". Do you mean "then" as in, "I
took off my coat and then sat down", as opposed to then in if/then?

Yes. Not much better than #tap, is it? Any ideas...? "and_then"?
 
D

dblack

Hi --

Yes. Not much better than #tap, is it? Any ideas...? "and_then"?

"whereupon" :) I guess it's hard to find a name that's general
enough (as opposed to, say, "post_initialize") but also expressive
enough. It does seem a slightly odd technique to me, in any case --
sort of like saying "Now I'm going to do this: this" instead of just
going to a new line and saying: "this". I'm not sure how much of the
oddness I feel is the technique as opposed to the naming issue.


David

--
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
 
J

Joel VanderWerf

Hi --



"whereupon" :) I guess it's hard to find a name that's general
enough (as opposed to, say, "post_initialize") but also expressive
enough. It does seem a slightly odd technique to me, in any case --
sort of like saying "Now I'm going to do this: this" instead of just
going to a new line and saying: "this". I'm not sure how much of the
oddness I feel is the technique as opposed to the naming issue.

Does the following technique seem odd?

class Foo
attr_accessor :a, :b, :c
def initialize
yield self if block_given?
end
end

foo = Foo.new do |f|
f.a = 1
f.b = 2
f.c = 3
end

#then is just a way of using arbitrary classes (or factories) in this
way. Maybe the name should not emphasize the temporal ("then" or
"whereupon"); so maybe "tap" is better, or "configured_using".

Btw, I don't think I've ever used #then in more than 5 or 6 places.
Usually, I just try to define classes like Foo above.
 
A

ara.t.howard

ROFL

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


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

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

indeed - good point.

-a
 
D

dblack

Hi --

Does the following technique seem odd?

class Foo
attr_accessor :a, :b, :c
def initialize
yield self if block_given?
end
end

foo = Foo.new do |f|
f.a = 1
f.b = 2
f.c = 3
end

#then is just a way of using arbitrary classes (or factories) in this way.
Maybe the name should not emphasize the temporal ("then" or "whereupon"); so
maybe "tap" is better, or "configured_using".

Part of what's odd to me about #then is that it's not
constructor-specific. Once it's defined you could do:

x = string.split(',').then do |array|
array.map! { something }
end

Bad example :) But that's what I meant about not giving it too
specific a name, like "post_initialize", since it's not restricted to
initialization scenarios.


David

--
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
 
M

Martin DeMello

Part of what's odd to me about #then is that it's not
constructor-specific. Once it's defined you could do:

x = string.split(',').then do |array|
array.map! { something }
end

"then" actually works fine for me there, Englishwise. Maybe and_then
would read slightly better:

string.split(',').and_then do |array|

martin
 
D

dblack

Hi --

"then" actually works fine for me there, Englishwise. Maybe and_then
would read slightly better:

string.split(',').and_then do |array|

I wonder if there's some name that embodies the fact that the object
is going to come back from this method call. The temporal ones (then,
and_then, etc.) sound kind of self-evident ("Well, of course the next
thing happens 'then'," my brain says). Perhaps that was the reasoning
behind "tap", though "tap" doesn't communicate much to me. I'm not
sure.


David

--
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
 
M

Martin DeMello

I wonder if there's some name that embodies the fact that the object
is going to come back from this method call. The temporal ones (then,
and_then, etc.) sound kind of self-evident ("Well, of course the next
thing happens 'then'," my brain says).

Good point! I thought of "pipe" but even that doesn't say that it
modifies and returns self. Maybe "apply": string.split(/\s/).apply
{|i| i.pop}.whatever. Or even "modify".
Perhaps that was the reasoning
behind "tap", though "tap" doesn't communicate much to me. I'm not
sure.

'tap' had a different intent, though - "tee off the object without
disturbing it" - even if it did the same thing in the end. So you
would typically take a.foo.bar.baz.quux... and drop in a tap,
a.foo.bar.tap {|i| puts "hi mom! this is #{i}"}.baz.quux, and take
care not to modify i destructively.

martin
 
S

spooq

I definitely think of it as tapping a phone line.

a.map.map.map.map

eavesdrop = Proc.new { |secret| puts secret }

a.map.map.tap(&eavesdrop) .map.map

It lets me get into the line and hear what's going on without changing
any existing behaviour. Using a proc that modifies secret is not a
good idea, just keep it for things with other types of side-effects.
There's no way to mark the object read-only for the purposes of the
passed-in proc, is there?

I haven't seen anything to change my mind about the other use. It just
seems pointless.
 
S

spooq

Actually, how about giving the proc a copy of the object, rather than
the real deal?

class Object
def tap
yield self.dup
self
end
end
 
M

Martin DeMello

Actually, how about giving the proc a copy of the object, rather than
the real deal?

class Object
def tap
yield self.dup
self
end
end

Thought of that, but not everything responds to dup (nil and symbols, e.g.)

m.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top