Changing enum_obj

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

T.

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 Gray II

···

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.

Ah, of course.

Thanks,
T.

···

On Jun 24, 12:26 am, James Edward Gray II <j...@grayproductions.net> 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.

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.

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

T.

···

On Jun 24, 12:32 am, Trans <transf...@gmail.com> wrote:

On Jun 24, 12:26 am, James Edward Gray II <j...@grayproductions.net> > 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.

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

···

On 6/24/07, Trans <transfire@gmail.com> wrote:

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.

  #
  # 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
--
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw

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.

···

On Jun 24, 4:15 am, "Robert Dober" <robert.do...@gmail.com> wrote:

On 6/24/07, Trans <transf...@gmail.com> wrote:

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

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

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

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

···

On 6/24/07, Trans <transfire@gmail.com> wrote:

On Jun 24, 4:15 am, "Robert Dober" <robert.do...@gmail.com> wrote:
> On 6/24/07, Trans <transf...@gmail.com> wrote:

--
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw

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.

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.

···

On Jun 24, 7:05 am, "Robert Dober" <robert.do...@gmail.com> wrote:

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

Oops , thx Tom.

···

T.

--
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw