Tap method : good or bad practice?

Hi all !

I try to code a function that generates and returns options. Is it
better to do this :

def options
options = {}
1.upto(31) { |i| options[i] = i }
options
end

Or this :

def options
{}.tap { |options| 1.upto(31) { |i| options[i] = i } }
end

What is the Ruby way of doing this ? Is it common to use this
trap method ? Thank you very much for your help (I’m new to Ruby) !

On Sun, Apr 21, 2013 at 12:56 AM, Sébastien Durand
[email protected] wrote:

end
What is the Ruby way of doing this ? Is it common to use this
trap method ? Thank you very much for your help (I’m new to Ruby) !

There is more than one way to do things.

def preset_options(n)
1.upto(n).reduce({}) {|o,i| o[i]=i; o}
end

The above doesn’t need to be wrapped in a method, though if it is an
oft-repeated motif, it should be.

On Sun, Apr 21, 2013 at 8:43 AM, tamouse mailing lists <
[email protected]> wrote:

There is more than one way to do things.

That’s true for sure. Why write all the values into the Hash? Here’s
my
take:

options = Hash.new {|h,k| k}

Kind regards

robert

Robert K. wrote in post #1106422:

On Sun, Apr 21, 2013 at 8:43 AM, tamouse mailing lists <
[email protected]> wrote:

There is more than one way to do things.

That’s true for sure. Why write all the values into the Hash? Here’s
my
take:

options = Hash.new {|h,k| k}

Kind regards

robert

Robert the Problem is the default proc, it is maybe not what he wants
because it pretend from marshaling

tap is an example of a K combinator. It might not be common practice,
though some probably use it without knowing, but it is good practice.

Henry

On Sun, 21 Apr 2013 07:56:50 +0200, Sébastien Durand
[email protected] wrote:

def options
options = {}
1.upto(31) { |i| options[i] = i }
options
end

def options
{}.tap { |options| 1.upto(31) { |i| options[i] = i } }
end

Well, which one looks easier to read and understand? For me it’s
obviously the first one. Number of lines of code is not a metric of
complexity.

On Sun, 21 Apr 2013 08:43:15 +0200, tamouse mailing lists
[email protected] wrote:

def preset_options(n)
1.upto(n).reduce({}) {|o,i| o[i]=i; o}
end

Uhh, and please don’t do this, either. If you need multiple expressions
inside reduce’s block, you’re doing it wrong.

If you really wanted to make it one expression, use a hash with default
like Robert suggested, or something like Hash[ (1..31).map{|n| [n, n] } ] - but frankly, your initial version looks the prettiest to me.

(On a completely unrelated note, because I felt like golfing: Hash[ (1..31).map &Array.method(:new).to_proc.curry(2).call(2) ].)

To better express the above reduce case:

1.upto(n).each_with_object({}) { |i,mem| mem[i]=i }

Can on the same context anyone explain the difference between tap and
inject ?

On Sun, Apr 21, 2013 at 11:32 AM, Hans M.
[email protected]wrote:

options = Hash.new {|h,k| k}

Robert the Problem is the default proc, it is maybe not what he wants
because it pretend from marshaling

Why is that a problem? Do you have knowledge about the situation of
Sbastien which other writers in this thread do not have? If not, why
are
you claiming there is problem?

Cheers

robert

On Sun, Apr 21, 2013 at 4:32 AM, Bartosz Dziewoński
[email protected] wrote:

Uhh, and please don’t do this, either. If you need multiple expressions
inside reduce’s block, you’re doing it wrong.

This is completely useless advice.

Why is it wrong?

The documentation has just such an example, as do many other places
describing the method. Whence comes your stricture? I find nothing
about it.

Regardless of the refactors people are suggesting, going to the original
question about tap I know people who like it and people who dislike it.
From my perspective I don’t think there’s consensus as to which form is
preferred.

Most of the times I use tap, because it conveys the intention to the
reader
that you are going to return that value. It is kind of declarative for
me.
But in a method like yours where there’s three lines I would not
normally
use it, since I believe people load those 3 lines in one shot in their
head
and the form without tap is probably more readable.

On Sun, Apr 21, 2013 at 12:56 AM, Sbastien D.
[email protected]wrote:

What is the Ruby way of doing this ? Is it common to use this
trap method ? Thank you very much for your help (I’m new to Ruby) !

I wouldn’t do that, unless I had a need to inline it (e.g. writing a
one-liner on the the command line), but I also wouldn’t care enough to
change it if I saw it in my codebase. It is totally irrelevant next to
concerns about object boundaries and mutability, so it seems to me that
any
disagreement is just bikeshedding.

On Sun, Apr 21, 2013 at 1:20 PM, Love U Ruby [email protected]
wrote:

Can on the same context anyone explain the difference between tap and
inject ?

Are the docs unclear?

On Apr 21, 2013 5:21 PM, “Josh C.” [email protected] wrote:

On Sun, Apr 21, 2013 at 12:56 AM, Sébastien Durand [email protected]
wrote:

What is the Ruby way of doing this ? Is it common to use this
trap method ? Thank you very much for your help (I’m new to Ruby) !

I wouldn’t do that, unless I had a need to inline it (e.g. writing a
one-liner on the the command line), but I also wouldn’t care enough to
change it if I saw it in my codebase. It is totally irrelevant next to
concerns about object boundaries and mutability, so it seems to me that
any
disagreement is just bikeshedding.

The thing I don’t like about using .tap in the way sown is that it feels
like a side effect, but admittedly that comes from my initial belief
about
the intention of .tap. As with most things, we find new uses for things
that weren’t originally thought of, and I find that good for the most
part.

tamouse mailing lists wrote in post #1106508:

The thing I don’t like about using .tap in the way sown is that it feels
like a side effect, but admittedly that comes from my initial belief
about
the intention of .tap. As with most things, we find new uses for things
that weren’t originally thought of, and I find that good for the most
part.

I often find myself using idioms like

Klass.new.tap do

end

with Klass = Hash, Array, … , and dreaming about a shortcut to
‘new.tap’ like ‘such_that’, ‘with’, …

-md

Robert K. wrote in post #1106648:

What is it that you want to achieve? Can you please come up with a more
realistic example?

Kind regards

robert

Hello Robert. I use this systematically, replacing for instance

def foo(args)
hsh = Hash.new

some lines building hsh by calling methods using args,

hsh
end

by

def foo(args)
Hash.new.tap do |hsh|
## same code as above
end
end

I find the latter cleaner and easier to read, due to the extra
indentation inside. I think Rails has a ‘returning’ method doing just
that.

_md

On Tue, Apr 23, 2013 at 12:05 PM, Michel D.
[email protected]wrote:

Klass.new.tap do

end

That doesn’t make any sense at all: there is no point in using #tap if
you
do not assign the result and not use the block parameter. (Note: #tap
does
not change self.) Or do you mean

Klass.new.instance_eval do

end

with Klass = Hash, Array, … , and dreaming about a shortcut to
‘new.tap’ like ‘such_that’, ‘with’, …

What is it that you want to achieve? Can you please come up with a more
realistic example?

Kind regards

robert

Thank you very much for your various answers !

:slight_smile:

Why this kind of loop from 1 to 31 ? These magic numbers are the days in
a month and I use them in a DaySelect class.

I decided to go with the most explicit implementation :

def options
options = {}
‘1’.upto(‘31’) do |day| options[day] = ‘%02d’ % day end
options
end

“tap”, “each_with_object” and so on are maybe overkill ? But
being new to
Ruby, this makes me realize that there is more than one way to do it and
Ruby fits everybody’s style.

(By the way, sorry for my poor english, I’m a french-speaking guy.)

On Sat, Apr 27, 2013 at 12:42 PM, Michel D.
[email protected]wrote:

I think Rails has a ‘returning’ method doing just

that.

Yeah, Active Support had “returning” in the past, but was removed in
Rails
3 in favor of Object#tap.