Feature #13904

getter for original information of Enumerator

Added by znz (Kazuhiro NISHIYAMA) about 1 month ago. Updated 29 days ago.

Target version:


At ,
mrkn says narray and pycall use internal information of ruby to check Range#step(n).

People of red-data-tools/ja suggest subclass of Enumerator.
But I think it does not match Ruby's '大クラス主義' (I don't know this word in English), so I suggest to add some methods to Enumerator class.

proof of concept attached.


% irb -r irb/completion --simple-prompt
>> e=(1..2).step(3)
=> #<Enumerator: 1..2:step(3)>
>> e.receiver
=> 1..2
>> e.method_name
=> :step
>> e.arguments
=> [3]

#method is conflict with Kernel#method, so use #method_name instead.

poc.diff (1.42 KB) poc.diff znz (Kazuhiro NISHIYAMA), 09/15/2017 03:27 PM


#1 [ruby-core:82822] Updated by zverok (Victor Shepelev) about 1 month ago


In fact, recently I became rather concerned with a lack of "inspectability" of Ruby's own objects (like "how #format would parse this string and what groups it has", or internal structure of Regexp and so on).

#2 [ruby-core:82826] Updated by Eregon (Benoit Daloze) about 1 month ago

I agree, I think it's a good idea to expose such information when it is available in #inspect and it is user-provided (not internal).

#3 [ruby-core:82840] Updated by knu (Akinori MUSHA) about 1 month ago

  • Assignee set to knu (Akinori MUSHA)

#4 [ruby-core:82847] Updated by knu (Akinori MUSHA) about 1 month ago

Enumerator is about abstracting enumeration and encapsulation of the source is by design. If we exposed the guts of an Enumerator, people would start to look into the enclosed object and do (I think are) evil things for optimization and specialization, which should be in the opposite direction of abstraction. If you expect something other than a one-way, not necessarily rewindable stream, I think you should create a new model that describes the aspect by sub-classing Enumerator or making a mix-in.

In summary, if you want to handle a numeric enumerator specially, I'd say you should create a class for that instead of making surrounding methods guess or find out what they receive is special by invesigating its internals. It shouldn't be a good way to introduce a new idea to the language.

#5 [ruby-core:82850] Updated by zverok (Victor Shepelev) 30 days ago

Enumerator is about abstracting enumeration and encapsulation of the source is by design.

Well, to be honest, it seems like "forced encapsulation", and is against Ruby's hackable nature.
I understand your concerns, but if something that even on #inspect looks like #<ClassName x:y> provides no access to x and y (though definitely knows them) it just "doesn't feel right".

I believe that composite objects (and enumerator by nature is composite: source + enumeration method) should provide access to what they are composed of, for bad or for good. It is completely possible new ways of interaction and new libraries would emerge in this case.

#6 [ruby-core:82852] Updated by shevegen (Robert A. Heiler) 30 days ago

evil things for optimization and specialization

Reminds me of good old evil.rb - now I am suddenly all for it! Just kidding. :-)

I have no particular pro or con opinion here but I think that one of ruby's philosophy is to put trust into the ruby hacker to do what he/she wants to do, e. g. duck patching modifying any of ruby's core functionality (class String, Array, Hash etc...), use .send() or .instance_variable_get() at leisure (I used this today to obtain @logged_in content in Net::FTP instances ... I think there is another method to access it, such as open?, but I saw the output of @logged in via pp, and thought I wanted to get the value, so I used instance_variable_get()) etc... ruby is very, very flexible. It's like a lispy-smalltalk-something OOP language. Encapsulation is possible but it also restricts what you can do (logically), so it is not always ruby's philosophy - to let the ruby hacker do what he/she wants, if he/she really wants to. This philosophy is also, I think, why constants in ruby are not 100% constants that can never be changed - ruby allows you to change constants. While the word constant may thus be a misnomer, I think it fits very well into the ruby philosophy overall.

In regards to encapsulation, that is why, I think, .public_send() was added and people can use that for the public/private distinction more clearly. I myself love .send(), freedom to all objects and especially all the duckling objects. \o/

By the way, the idea of composite objects reminds me a bit of what matz wrote about interface objects (specification where objects could/should respond to the same method-behaviour ... all ducks should be able to quack and swim ... so if something quacks and swims, even if it is a wolf disguised as a sheep, it may be treated to be an "acceptable duck").

But as said, I really am neutral here either way. :-)

Perhaps the ruby core team can discuss this a bit (I don't know japanese so I do not know what thoughts are conveyed above).

#7 [ruby-core:82856] Updated by knu (Akinori MUSHA) 29 days ago

Well, this issue states that the motivation for introducing the getter methods is for getting return values of Range#step(n) to be handled specially by some libraries or individual methods, and as I said it is to me a typical misuse of such accessors I've been thinking of and I believe there's a better way to achieve the goal, so I can't buy that argument.

I can hardly believe you'd be happy (at the cost of introducing a new feature) if you had to check x.instance_of?(Enumerator) && x.receiver.is_a?(Numeric) && x.method_name == :step every time your method was passed an object that might be a step object. It really looks like you are doing some hack as the last resort because you don't have anything better yet. If stepped range objects are useful, they deserve a new class for their own.

Also available in: Atom PDF