Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is ARGF.class in Ruby 1.9?

In Ruby 1.8.7, the documentation does not list ARGF under classes and modules, and ARGF isn't a class or a module:

ARGF.class # => Object

In Ruby 1.9.3, the documentation has ARGF under classes and modules, but I see this:

ARGF.class # => ARGF.class
ARGF.superclass # => NoMethodError: undefined method `superclass' for ARGF:ARGF.class
ARGF.class.superclass # => Object
  • Why does Ruby 1.9 documentation place ARGF as a class when the actual class is something else? Or are they the same thing?
  • Is ARGF.class a metaclass, a virtual class, singleton class, or something else?
like image 296
Ray Toal Avatar asked Sep 05 '12 04:09

Ray Toal


3 Answers

ARGF is implemented in C and you can do weird things in it. The ARGF class is defined there first. It is not set to any constant in Ruby, but its name is set to "ARGF.class". Then ARGF constant is set to an instance of that class.

rb_cARGF = rb_class_new(rb_cObject);
rb_set_class_path(rb_cARGF, rb_cObject, "ARGF.class");
/* ... */
argf = rb_class_new_instance(0, 0, rb_cARGF);
rb_define_global_const("ARGF", argf);

Here is a Ruby code that is doing roughly the same thing.

argf_class = Class.new
def argf_class.name
  "ARGF.class"
end
argf = argf_class.new
ARGF = argf

It does not look reasonable in Ruby, but in C it is fine. Although, I think the class could be set to ARGFClass like NilClass, TrueClass, FalseClass, so that it is not confusing.

I don't know the history of the change. I think Ruby core folks wanted to get ARGF into the docs and this was the simplest way. (RDoc can't show documentation for singleton objects.)

like image 151
Simon Perepelitsa Avatar answered Nov 14 '22 19:11

Simon Perepelitsa


It seems correct that ARGF is not a class or a module.

class ARGF
end
# => TypeError: ARGF is not a class

module ARGF
end
# => TypeError: ARGF is not a module

The documentation lists ARGF under class, but other than that, it does not say it is a class. Probably, it was not intended that ARGF handled as a class, and it is wrong of the documentation to have listed as such. It is the documentation's bug.

It looks like ARGF if the only instance of a certain class, which lacks a literal, and the only way to refer to it is to call ARGF.class.

ARGF.class.class
# => Class

ARGF.class.ancestors
# => [ARGF.class, Enumerable, Object, Kernel, BasicObject]

The usual relation between class and its instance holds for ARGF.class and ARGF.

ARGF.is_a?(ARGF.class)
# => true

ARGF.kind_of?(ARGF.class)
# => true
like image 32
sawa Avatar answered Nov 14 '22 20:11

sawa


If we capture the objects and look at them using just pure Ruby we can see a few things:

1.9.3 (Object#main):0 > ARGFClass = ARGF.class                                                                                                                                      
=> ARGF.class
1.9.3 (Object#main):0 > ARGFClass.name                                                                                                                                              
=> "ARGF.class"
1.9.3 (Object#main):0 > ARGFClass.class                                                                                                                                             
=> Class
1.9.3 (Object#main):0 > ARGFClass.superclass                                                                                                                                        
=> Object
1.9.3 (Object#main):0 > ARGFClass.ancestors                                                                                                                                         
=> [ARGF.class,
    Enumerable,
    Object,
    JSON::Ext::Generator::GeneratorMethods::Object,
    PP::ObjectMixin,
    Kernel,
    BasicObject]

For some reason, the developers have explicitly set the class.name value to return ARGF.class, which is generally uncommon but is used internally in Ruby for constants that should never be accessed directly.

We can instantiate objects with the ARGFClass exactly the same as any other class. That means it is a real Ruby class:

1.9.3 (Object#main):0 > argfinstance = ARGFClass.new                                                                                                                                
=> ARGF
1.9.3 (Object#main):0 > argfinstance.inspect                                                                                                                                        
=> "ARGF"

It's not just returning the singleton when you call #new either:

1.9.3 (Object#main):0 > argfinstance == ARGF                                                                                                                                        
=> false
1.9.3 (Object#main):0 > argfinstance.object_id                                                                                                                                      
=> 70346556507420
1.9.3 (Object#main):0 > ARGF.object_id                                                                                                                                              
=> 70346552343460

The Ruby developers have intentionally named the ARGF.class in such a way that it can't be referenced directly by name, but it is a real class and ARGF is a real object.

It has a lot of the same methods as an IO object, and in fact is defined in the io.c source file. It also has the Enumerable module mixed in so it supports all the each/inject/map functionality.

edit: The documentation lists ARGF as a class. However, its actually a constant referencing a singleton instance of the oddly named ARGF.class class.

References

  • https://groups.google.com/forum/?fromgroups=#!searchin/ruby-talk-google/argf.class/ruby-talk-google/ADQI5rhuJms/1M8I4_MpjuwJ
  • http://rubydoc.info/stdlib/core/ARGF
like image 24
Anthony Michael Cook Avatar answered Nov 14 '22 19:11

Anthony Michael Cook