Forum: Ruby Changing enum_obj

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
45196398e9685000d195ec626d477f0e?d=identicon&s=25 Trans (Guest)
on 2007-06-24 06:08
(Received via mailing list)
Anyway to change an Enumerator's enum_obj in place? Enumerator doesn't
seem to support the #collect! method.

T.
4299e35bacef054df40583da2d51edea?d=identicon&s=25 James Gray (bbazzarrakk)
on 2007-06-24 06:28
(Received via mailing list)
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 Gray II
45196398e9685000d195ec626d477f0e?d=identicon&s=25 Trans (Guest)
on 2007-06-24 06:33
(Received via mailing list)
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.

Thanks,
T.
45196398e9685000d195ec626d477f0e?d=identicon&s=25 Trans (Guest)
on 2007-06-24 07:06
(Received via mailing list)
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.
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-06-24 10:15
(Received via mailing list)
On 6/24/07, Trans <transfire@gmail.com> 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
45196398e9685000d195ec626d477f0e?d=identicon&s=25 Trans (Guest)
on 2007-06-24 12:36
(Received via mailing list)
On Jun 24, 4:15 am, "Robert Dober" <robert.do...@gmail.com> 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.
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-06-24 13:05
(Received via mailing list)
On 6/24/07, Trans <transfire@gmail.com> 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 :(

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 ;)
 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
45196398e9685000d195ec626d477f0e?d=identicon&s=25 Trans (Guest)
on 2007-06-24 13:35
(Received via mailing list)
> That is even broken in Labrador, so much work to do :(
>
> 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.
45196398e9685000d195ec626d477f0e?d=identicon&s=25 Trans (Guest)
on 2007-06-24 13:40
(Received via mailing list)
On Jun 24, 12:32 am, Trans <transf...@gmail.com> 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.
45196398e9685000d195ec626d477f0e?d=identicon&s=25 Trans (Guest)
on 2007-06-24 14:07
(Received via mailing list)
On Jun 24, 7:05 am, "Robert Dober" <robert.do...@gmail.com> 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 ;) 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 ;)
>  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.
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-06-24 15:03
(Received via mailing list)
>
> I think that's right, * takes precedence. So you're getting the result
> of '+ 6'.
Oops , thx Tom.
This topic is locked and can not be replied to.