With

Sorry folks if this was raised already, but google is not very
useful when asked for “ruby with” or “ruby map single object” …

Is there something like “with” already available? Let me give the
short implementation first so the gurus know right away what I am after:

module Kernel
def with
yield self
end
end

What does it do? It can glue an object and a block together. Just
append “.with {|x| block}” to your object. What’s that good for?

When I have an array (or range or similar) and I want to do
something with each member, I can already do that by simply adding
“.map {|elem| do_something_with(elem)}”. The result can be used
transparently within another calculation. #each, #map and #inject
are good candidates for something like that. So far, so good.

Take the following situation:

result= a_long_calculation_start …
… a_very_long_object_calculation …
… calculation_end

What can I do now if I have to apply a function on
“a_very_long_object_calculation” in the example above? Since
a_very_long_object_calculation is not an array, I cannot use
#each/#map/#inject. So let’s put the function call around the
calculation:

Solution 1:

result= a_long_calculation_start …
… function(a_very_long_object_calculation) …
… calculation_end

But what if “function” is an in-place calculation containing of if’s
and loops? Then I have to move all that away from the long object
calculation:

Solution 2:

intermediate= a_very_long_object_calculation
intermediate_result= function(intermediate)
result= a_long_calculation_start …
… intermediate_result …
… calculation_end

Obviously, while reaching the goal, the function is now ugly
disrupted. Even Solution 1 suffers from the fact that I have to at
least put some text into the expression before
a_very_long_object_calculation appears. What would be nice if I
could implement the in-place calculation inside of a block like with
#each, #map or #inject:

result= a_long_calculation_start …
… a_very_long_object_calculation.with{|val| function(val)} …
… calculation_end

With “with”, the following proportions are solved:

  1. I can put arbitrary functions into the block following #with.

  2. I don’t have to put additional characters before
    a_very_long_object_calculation – succeeding calculations are behind
    the preceding object calculation.

Am I the first to ask for something like this or is this already
implemented in a way that I couldn’t find it?

BTW: “with” could be renamed to something short and similar – f.e.
.smap (single map), so there could be a .seach (single each) as well
returning “self” after the yield. .sinject is not very useful.

module Kernel
def smap
yield self
end
def seach
yield self
self
end
end

Thanks,

  • Matthias

On 03.09.2007 17:15, Matthias Wächter wrote:

end

calculation:

least put some text into the expression before

  1. I can put arbitrary functions into the block following #with.
    returning “self” after the yield. .sinject is not very useful.

Thanks,

  • Matthias

Somewhere above you completely lost me - it is especially unclear to me
what “a_very_long_calculation” is supposed to be. Is this a variable
name? Is this a placeholder for a long expression?

Anyway, I do wonder whether all this can be nicely solved by using local
variables. Basically #with does nothing else than binding a value to a
local variable with limited scope.

Kind regards

robert

Robert K. schrieb:

Somewhere above you completely lost me - it is especially unclear to me
what “a_very_long_calculation” is supposed to be. Is this a variable
name? Is this a placeholder for a long expression?

It’s the latter.

Suppose you do a calculation like the following:

a=[“abc”,“thing”].
map{|x| x.length}.
inject(0){|sum,x|sum+x}.
to_f**0.5

(this is only for the sake of example, don’t try to make sense out of
it).

When I want to insert a function between .map and .inject, I can simply
do that:

a=[“abc”,“thing”].
map{|x| x.length}.
map{|x| x>5 ? 5 : x}.
inject(0){|sum,x|sum+x}.
to_f**0.5

I don’t have to change any part of the expression before or after my
change, it’s just an insert.

But I can’t do the same for values that are not arrays. Say, after .to_f
I want to set bounds on the value so that the square root function does
not raise an exception. Then .with is useful.

a=[“abc”,“thing”].
map{|x| x.length}.
map{|x| x>5 ? 5 : x}.
inject(0){|sum,x|sum+x}.
to_f.
with{|f| f<0.0 ? 0.0 : f}**0.5

Otherwise I’d have to split execution at this place, assign to a
temporary variable, make my calculation and continue the expression
later on.

temp=[“abc”,“thing”].
map{|x| x.length}.
map{|x| x>5 ? 5 : x}.
inject(0){|sum,x|sum+x}.
to_f
if temp<0.0
temp = 0.0
end
a=temp**0.5

I like the ‘with’ version better.

Anyway, I do wonder whether all this can be nicely solved by using local
variables. Basically #with does nothing else than binding a value to a
local variable with limited scope.

Ruby tries to avoid local variables wherever it can by chaining
iterators together like in file-open-each-line-gsub. I tried to allow a
block to be used for non-enumerable types as well.

What .with does is producing a little space for writing a block instead
of requiring to reorder the whole function just for adding this little
piggy-bag change.

Does it make sense now?

  • Matthias

Matthias Wächter wrote:

 map{|x| x.length}.
 inject(0){|sum,x|sum+x}.
 to_f.
 with{|f| f<0.0 ? 0.0 : f}**0.5

Otherwise I’d have to split execution at this place, assign to a temporary variable, make my calculation and continue the expression later on.

So “with” lets you keep the chain going.
This won’t do that, but it avoids a temporary variable:

a =
[ [“abc”,“thing”].
map{|x| x.size }.
map{|x| x>5 ? 5 : x}.
inject{|sum,x| sum + x }.
to_f, 0.0 ].max ** 0.5

As suggested by someone else, “instance_eval” can
be used:

a =
[“abc”,“thing”].
map{|x| x.size }.
map{|x| x>5 ? 5 : x}.
inject{|sum,x| sum + x }.
to_f.instance_eval{ [self, 0.0].max} ** 0.5

Matthias Wächter wrote:

Sorry folks if this was raised already, but google is not very
useful when asked for “ruby with” or “ruby map single object” …

Is there something like “with” already available? Let me give the
short implementation first so the gurus know right away what I am after:

module Kernel
def with
yield self
end
end

What does it do? It can glue an object and a block together. Just
append “.with {|x| block}” to your object. What’s that good for?

snip (ruby-forum.com doesn’t like too much quoted text)

Thanks,

  • Matthias

Sometimes less is more :wink:
I’m not sure I really undestood what you want, but maybe instance_eval
is what you want or at least comes close to it.

Regards
Stefan

Hi,

At Tue, 4 Sep 2007 00:15:32 +0900,
Matthias Wächter wrote in [ruby-talk:267357]:

Is there something like “with” already available? Let me give the
short implementation first so the gurus know right away what I am after:

module Kernel
def with
yield self
end
end

“tap” in 1.9 is same.

On 03.09.2007 23:50, Matthias Wächter wrote:

 map{|x| x.length}.
 inject(0){|sum,x|sum+x}.
 to_f.

temp = 0.0

What .with does is producing a little space for writing a block instead of requiring to reorder the whole function just for adding this little piggy-bag change.

Does it make sense now?

Yes, thank you for the explanation! I know now what you were after. I
am not sure I’d subscribe to the Ruby “tries to avoid local variables”.

Kind regards

robert

On 9/4/07, Nobuyoshi N. [email protected] wrote:

end
end

“tap” in 1.9 is same.

They have different effects, while ‘tap’ will return self and throw
away results of the block, ‘with’ returns the result of the block.

[[email protected] ~]$ RUBYOPT= irb19
class Object
def with
yield(self)
end
end

nil

1.tap{|e| e + 1} + 2

3

1.with{|e| e + 1} + 2

4

^ manveru

On 04.09.2007 09:47, Michael F. wrote:

On 9/4/07, Nobuyoshi N. [email protected] wrote:

“tap” in 1.9 is same.

Great to hear that this is really not available yet :slight_smile: and I’m not
the only one thinking it should be!

1.tap{|e| e + 1} + 2

3

1.with{|e| e + 1} + 2

4

So it’s like .with == .single-map, .tap == .single-each

Right?

  • Matthias

On 9/4/07, Matthias Wächter [email protected] wrote:

[[email protected] ~]$ RUBYOPT= irb19

So it’s like .with == .single-map, .tap == .single-each

Right?

Exactly :slight_smile:

^ manveru

Hi,

At Tue, 4 Sep 2007 16:47:07 +0900,
Michael F. wrote in [ruby-talk:267472]:

They have different effects, while ‘tap’ will return self and throw
away results of the block, ‘with’ returns the result of the block.

Sorry.

1.tap{|e| e + 1} + 2

3

1.with{|e| e + 1} + 2

4

1.tap{|e| break e + 1} + 2

4

On Tue, Sep 04, 2007 at 06:50:43AM +0900, Matthias W?chter wrote:

Anyway, I do wonder whether all this can be nicely solved by using local
variables. Basically #with does nothing else than binding a value to a
local variable with limited scope.

Ruby tries to avoid local variables wherever it can by chaining
iterators together like in file-open-each-line-gsub. I tried to allow
a block to be used for non-enumerable types as well.

Ruby doesn’t try to avoid local variables; this is something you have
done. IMO it’s not a good idea. If there’s a bug anywhere in your
chain and one of the methods you call returns the wrong type (nil, for
example), then debugging becomes more difficult.

Paul

On 04.09.2007 15:28, Paul B. wrote:

On Tue, Sep 04, 2007 at 06:50:43AM +0900, Matthias W?chter wrote:

Ruby tries to avoid local variables wherever it can by chaining
iterators together like in file-open-each-line-gsub. I tried to allow
a block to be used for non-enumerable types as well.

Ruby doesn’t try to avoid local variables; this is something you have
done. IMO it’s not a good idea. If there’s a bug anywhere in your
chain and one of the methods you call returns the wrong type (nil, for
example), then debugging becomes more difficult.

Flow is generally from top to bottom (in a file) and from left to
right in a line. If there were not function calling and assignment
which work some kind of upstream, i.e. right to left. .with
introduces downstream function calling without the need for
rewriting code around the whole statement and introducing more
variables.

It even helps debugging. If I am not sure about a value I can simply
add “.with {|x| puts “Debugging the expression: #{x}”}” within an
expression. Certainly, I might have to add a paren around the
expression for ordering stuff correctly, but I don’t have to split
things apart.

FWIW, I have not touched the field of debugging with Ruby yet, so
allow me a second opinion on this later :slight_smile:

  • Matthias

On Tue, Sep 04, 2007 at 11:15:58PM +0900, Matthias W??chter wrote:

It even helps debugging. If I am not sure about a value I can simply
add “.with {|x| puts “Debugging the expression: #{x}”}” within an
expression. Certainly, I might have to add a paren around the
expression for ordering stuff correctly, but I don’t have to split
things apart.

I’m not arguing against the utility of “with”, but against method
chaining, which in my experience causes more problems than it solves. I
tend to label code that uses method chaining more as “clever” than as
“beautiful”.

My experience may or may not be indicative of the experience of the
average ruby programmer.

Paul

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs