[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Matthias Wächter

9/3/2007 3:16:00 PM

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

13 Answers

Robert Klemme

9/3/2007 7:27:00 PM

0

On 03.09.2007 17:15, 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?
>
> 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
>

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

Matthias Wächter

9/3/2007 9:51:00 PM

0

Robert Klemme 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

Stefan Rusterholz

9/3/2007 10:01:00 PM

0

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 ;-)
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
--
Posted via http://www.ruby-....

William James

9/3/2007 10:55:00 PM

0


Matthias W?chter wrote:
> Robert Klemme 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.

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

Robert Klemme

9/4/2007 5:27:00 AM

0

On 03.09.2007 23:50, Matthias Wächter wrote:
> Robert Klemme 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?

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

Nobuyoshi Nakada

9/4/2007 5:53:00 AM

0

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.

--
Nobu Nakada

Michael Fellinger

9/4/2007 7:47:00 AM

0

On 9/4/07, Nobuyoshi Nakada <nobu@ruby-lang.org> wrote:> 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.They have different effects, while 'tap' will return self and throwaway results of the block, 'with' returns the result of the block.[manveru@pi ~]$ RUBYOPT= irb19class Object def with yield(self) endend# nil1.tap{|e| e + 1} + 2# 31.with{|e| e + 1} + 2# 4^ manveru

Matthias Wächter

9/4/2007 7:53:00 AM

0

On 04.09.2007 09:47, Michael Fellinger wrote:
> On 9/4/07, Nobuyoshi Nakada <nobu@ruby-lang.org> wrote:
>> "tap" in 1.9 is same.

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

> They have different effects, while 'tap' will return self and throw
> away results of the block, 'with' returns the result of the block.
>
> [manveru@pi ~]$ 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

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

Right?

- Matthias

Michael Fellinger

9/4/2007 8:00:00 AM

0

On 9/4/07, Matthias Wächter <matthias@waechter.wiz.at> wrote:> On 04.09.2007 09:47, Michael Fellinger wrote:> > On 9/4/07, Nobuyoshi Nakada <nobu@ruby-lang.org> wrote:> >> "tap" in 1.9 is same.>> Great to hear that this is really not available yet :) and I'm not> the only one thinking it should be!>> > They have different effects, while 'tap' will return self and throw> > away results of the block, 'with' returns the result of the block.> >> > [manveru@pi ~]$ 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>> So it's like .with == .single-map, .tap == .single-each>> Right?Exactly :)^ manveru

Nobuyoshi Nakada

9/4/2007 8:25:00 AM

0

Hi,

At Tue, 4 Sep 2007 16:47:07 +0900,
Michael Fellinger 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

--
Nobu Nakada