Changing enum_obj


#1

Anyway to change an Enumerator’s enum_obj in place? Enumerator doesn’t
seem to support the #collect! method.

T.


#2

On Jun 23, 2007, at 11:07 PM, Trans wrote:

Anyway to change an Enumerator’s enum_obj in place? Enumerator doesn’t
seem to support the #collect! method.

Knowing that an object is Enumerable doesn’t tell you anything about
how to edit it, so there’s no way Enumerable could logically support
destructive operations.

James Edward G. II


#3

On Jun 24, 12:26 am, James Edward G. II removed_email_address@domain.invalid
wrote:

On Jun 23, 2007, at 11:07 PM, Trans wrote:

Anyway to change an Enumerator’s enum_obj in place? Enumerator doesn’t
seem to support the #collect! method.

Knowing that an object is Enumerable doesn’t tell you anything about
how to edit it, so there’s no way Enumerable could logically support
destructive operations.

Ah, of course.

Thanks,
T.


#4

Well, I might as well bring up the reason I asked about enum_obj…

Spending some time improving Facets’ Elementor class concept and
#every method, I find this possible utter simplification:

class Enumerable::Enumerator
def method_missing(sym, *args, &blk)
self.class.new(collect{ |e| e.send(sym, *args, &blk) })
end
end

Example:

a = [1,2,3]
e = a.to_enum
e += 3
e *= 2
e.to_a #=> [8,10,11]

T.


#5

On 6/24/07, Trans removed_email_address@domain.invalid wrote:

Example:

a = [1,2,3]
e = a.to_enum
e += 3
e *= 2
e.to_a #=> [8,10,11]

T.

Apart the magic dot notation that is exactly what I am doing in
Labrador.
Well I cannot expect blocks in this way as they have the original
purpose and are sent to map.

module Enumerable

alias_method :__map_l1, :map

The behavior of map {…} is unchanged.

map(arg1, *rest) simply is translated to map{ |ele| ele.send(arg1,

*rest) }

map(arg1, *rest){…} is translated to map{|ele|

ele.send(arg1,*rest}.map{…}

map without any arguments creates a Dispatcher Proxy that will

dispatch all messages

to the elements of the receiver.

All the following expressions evaluate therefore to the same result:

ary=[*0…9]

ary.map{ |x| x + 1}

ary.map(:succ)

ary.map.succ

ary.map(:+, 1)

ary.map + 1

def map *args, &blk
return Labrador::Dispatcher.new( self, :map ) if args.empty? &&
blk.nil?
return __map_l1( &blk ) if args.empty?
return __map_l1 { |x| x.send( *args ) } if blk.nil?
__map_l1 { |x| x.send( *args ) }.__map_l1( &blk )
end # def map *args, &blk

end # module Enumerable

Robert


#6

On Jun 24, 4:15 am, “Robert D.” removed_email_address@domain.invalid wrote:

def method_missing(sym, *args, &blk)

e.to_a #=> [8,10,11]

ary.map{ |x| x + 1}

end # module Enumerable

Ah, so you overloaded #map with this functionality. That’s similar to
what I had done, but I used a different method name, #every, which is
defined:

module Enumerable
def every
@_functor_every ||= Functor.new do |op,*args|
self.collect{ |a| a.send(op,*args) }
end
end
end

Both are limited in one common respect. They can’t be chained along
without repeated invocation, eg. it’s not

[1,2,3].map * 6 + 4

We have to do:

([1,2,3].map * 6).map + 4

Not quite as bad for #map, as opposed to #every, being shorter, but it
would still be nice to chain. Of course, to do that one must
explicitly #to_a the final result per my original Enumerator example.

One thing you might want to consider, Ruby 1.9+ returns an Enumerator
for #map without a block, could pose some compatibility issues in the
future. Though, I have to admit I’m not quite sure what a #map based
Enumerator is good for – when you run #each on it, it acts like
#map !!!

T.


#7

That is even broken in Labrador, so much work to do :frowning:

irb(main):001:0> require ‘labrador’
=> true
irb(main):002:0> [1,2,3].map + 2
=> [3, 4, 5]
irb(main):003:0> [1,2,3].map + 2 * 3
=> [7, 8, 9] *** Arrrgh

I think that’s right, * takes precedence. So you’re getting the result
of ‘+ 6’.

T.


#8

On 6/24/07, Trans removed_email_address@domain.invalid wrote:

#every method, I find this possible utter simplification:
e = a.to_enum
module Enumerable

return __map_l1 { |x| x.send( *args ) } if blk.nil?
__map_l1 { |x| x.send( *args ) }.__map_l1( &blk )

end # def map *args, &blk

end # module Enumerable

Ah, so you overloaded #map with this functionality. That’s similar to
what I had done, but I used a different method name, #every, which is
defined:
Facets is great but Labrador is mine, what does that mean: I have the
luxury to do things that scale badly and break compatibility, – I
have to make the documentation clear about this in the next version.
Facets is a General Purpose Library and cannot afford that luxury, so
it is very clear why you have #every – a tempting idea not to
overload map, even in an experimental package as my dog package. Yet
another advantage, I just change the name, nobody can complain…
OTH I am surprised that #every corresponds to #map, from its naming on
would say it should correspond to #each.

module Enumerable
def every
@_functor_every ||= Functor.new do |op,*args|
self.collect{ |a| a.send(op,*args) }
end
end
end

I gotta look at your Functors again, maybe I can steal a little bit from
you;)

Both are limited in one common respect. They can’t be chained along
without repeated invocation, eg. it’s not

[1,2,3].map * 6 + 4
That is even broken in Labrador, so much work to do :frowning:

irb(main):001:0> require ‘labrador’
=> true
irb(main):002:0> [1,2,3].map + 2
=> [3, 4, 5]
irb(main):003:0> [1,2,3].map + 2 * 3
=> [7, 8, 9] *** Arrrgh

We have to do:

([1,2,3].map * 6).map + 4

Not quite as bad for #map, as opposed to #every, being shorter, but it
would still be nice to chain. Of course, to do that one must
explicitly #to_a the final result per my original Enumerator example.

One thing you might want to consider, Ruby 1.9+ returns an Enumerator
for #map without a block, could pose some compatibility issues in the
future.
That is a good thing, and thanks for pointing it out, looking for a
different name for #map now :wink:
Though, I have to admit I’m not quite sure what a #map based
Enumerator is good for – when you run #each on it, it acts like
#map !!!

T.

Cheers
Robert


#9

On Jun 24, 12:32 am, Trans removed_email_address@domain.invalid wrote:

destructive operations.

Ah, of course.

Wait. Yes, the #collect! method isn’t going to fly, but if I could
just reassign enum_object – that would actually better.

T.


#10

On Jun 24, 7:05 am, “Robert D.” removed_email_address@domain.invalid wrote:

Facets is great but Labrador is mine, what does that mean: I have the
luxury to do things that scale badly and break compatibility, – I
have to make the documentation clear about this in the next version.
Facets is a General Purpose Library and cannot afford that luxury, so
it is very clear why you have #every – a tempting idea not to
overload map, even in an experimental package as my dog package. Yet
another advantage, I just change the name, nobody can complain…
OTH I am surprised that #every corresponds to #map, from its naming on
would say it should correspond to #each.

Yes, but #each is taken too :wink: I though about #each? though.

module Enumerable
def every
@_functor_every ||= Functor.new do |op,*args|
self.collect{ |a| a.send(op,*args) }
end
end
end

I gotta look at your Functors again, maybe I can steal a little bit from you;)

Basic Functor is easy:

class Functor
private *instance_methods
def initialize(&function)
@function = function
end
def method_missing(sym,*args,&blk)
@function.call(sym,*args,&blk)
end
end

Facets’ is a little more fleshed out than that, but that’s all one
needs. And I still think it worthy of inclusion in Ruby’s standard
library.

That is a good thing, and thanks for pointing it out, looking for a
different name for #map now :wink:
Though, I have to admit I’m not quite sure what a #map based> Enumerator is good for – when you run #each on it, it acts like

#map !!!

I may have a solution for you:

require ‘enumerator’

class Enumerable::Enumerator
def method_missing(sym,*args,&blk)
each{ |x| x.send(sym,*args,&blk) }
end
end

With 1.9+ you’ll get what you want (mostly). For 1.8, you just need to
override map to return the Enumerator (just like 1.9 does). Btw, if
you do the same for #select:

[1,2,3].select < 2 #=> [1]

Oh, I am soooo tempted to put this in Facets.

T.


#11

I think that’s right, * takes precedence. So you’re getting the result
of ‘+ 6’.
Oops , thx Tom.