Understanding Ruby Classes, Objects and Methods

Dear Rubyists,

I recently wrote a document about Ruby’s classes, objects and methods.
The goal was to find out whether I understand them right and whether I
can explain it simply enough in writing.

It is available on the Google Drive:

With the help of some text, a few pictures and some examples, it tries
to explain these basic concepts in Ruby. I have taken help from Dave
Thomas’s book and Matz/Flanagan book but the document is my own
interpretation. It has become rather long, but I have worked hard on
being correct and precise.

I will be honored if you read and review (and help correct errors in)
the document.

Thanks and Best Regards,
Kedar M.

On Wed, Mar 13, 2013 at 11:20 PM, Kedar M. [email protected]
wrote:

to explain these basic concepts in Ruby. I have taken help from Dave
Thomas’s book and Matz/Flanagan book but the document is my own
interpretation. It has become rather long, but I have worked hard on
being correct and precise.

I will be honored if you read and review (and help correct errors in)
the document.

abc is an instance of String
This is not true. Said expression is a constructor of a String which
will return a different String instance on every evaluation.

“Depending upon the data type of the object, a variable is a name for
the object itself or a reference to it.”
In an introductory text I would not start with this statement.
Better: “A variable is a place that stores a reference to an object.”

Same for your treatment of “immediate values”. This is really an
implementation detail which should be taught much later. I think it
helps understanding if one does not bring this up that early.
Actually, from a point of view of the user of the language it does not
matter at all (only for performance, but not functionality wise).

“If the method were not found in String, Ruby would have followed the
superclass (sc, green arrow) links in search for the method
definition.” and “It creates a new anonymous class object and inserts
it into Foos superclass chain!”
This is not true. The chain of classes and modules found via
Module#ancestors is traversed instead. There is no need for a new
anonymous class. The only place where new classes are automatically
allocated is the singleton class of an instance.

I stopped reading there as I found your diagram about singleton quite
complicated and unclear.

Cheers

robert

On Thu, Mar 14, 2013 at 1:57 PM, Kedar M. [email protected]
wrote:

Thanks, Robert!

You’re welcome!

abc is an instance of String
This is not true. Said expression is a constructor of a String which
will return a different String instance on every evaluation.

I don’t find that statement in the doc. I only have:

  1. “abc” is an instance of String.

Yes, that’s it.

and I believe that is correct because String is the class of all strings
in Ruby.

irb(main):001:0> 5.times { s = “abc”; p s.object_id }
-1073589128
-1073589178
-1073589208
-1073589228
-1073589268
=> 5

I agree. But integers is what many of us start with playing in irb. So,
I thought it was appropriate to recognize the difference between
instances of String (e.g. “abc”) and those of an Integer (e.g. 1).

The fact that Fixnums are immediate values is completely irrelevant
for how they are used.

book) to what I wrote. The topic is about including Modules in Classes.
I don’t have the book handy. Maybe you can quote the relevant text.

Even if you say that the chain returned by ancestors is traversed, where
is the reference for code for something like Mod#m? Since the same
module Mod can be included in several classes, an instance of anonymous
class for each including class seems right. But I agree, I don’t yet
know how this happens internally in the interpreter.

So you say you do not know how it works but claim there is an
anonymous class - solely because it “seems right”? Why does it “seem
right”? I had though you wanted to convey facts.

Also, I tried to logically explain why included module’s methods have
to
get preference over those inherited from superclasses.

You do not need anonymous classes for that.

I stopped reading there as I found your diagram about singleton quite
complicated and unclear.

Not a problem. I will try to clarify the diagrams. Alas, they are not
doing their job :-(. But I believe they are correct (and this stuff is
complex).

I didn’t say “all”. Just the singleton class diagram put me off.

Cheers

robert

abc is an instance of String
This is not true. Said expression is a constructor of a String which
will return a different String instance on every evaluation.

I don’t find that statement in the doc. I only have:

  1. “abc” is an instance of String.

Yes, that’s it.

And do you suggest that that statement is “not true”?

and I believe that is correct because String is the class of all strings
in Ruby.

The fact that Fixnums are immediate values is completely irrelevant
for how they are used.

Perhaps. All I wanted to say was is reference to the phrase “is a”.
That’s when I introduced variables and I thought the difference in
intermediate values and references should be clarified at that point.
Since then, I have clarified the text even further.

book) to what I wrote. The topic is about including Modules in Classes.
I don’t have the book handy. Maybe you can quote the relevant text.

Even if you say that the chain returned by ancestors is traversed, where
is the reference for code for something like Mod#m? Since the same
module Mod can be included in several classes, an instance of anonymous
class for each including class seems right. But I agree, I don’t yet
know how this happens internally in the interpreter.

So you say you do not know how it works but claim there is an
anonymous class - solely because it “seems right”? Why does it “seem
right”? I had though you wanted to convey facts.

Yes. And I should really know what happens internally. But here is what
Dave says in his book (on page 379 of the Programming Ruby PDF –
Version: 2010-11-15 that I purchased from Prag Prog):


To get around this, Ruby uses a clever trick. When you include a module
in class Example, Ruby constructs a new class object, makes it the
superclass of Example, and then sets the superclass of the new class to
be the original superclass of Example. It then references the module
from this new class object in such a way that when you look a method up
in this class, it actually looks it up in the module, as shown in Figure
24.5, on the next page.

Is this not right?

Thanks, Robert!

abc is an instance of String
This is not true. Said expression is a constructor of a String which
will return a different String instance on every evaluation.

I don’t find that statement in the doc. I only have:

  1. “abc” is an instance of String.

and I believe that is correct because String is the class of all strings
in Ruby.

“Depending upon the data type of the object, a variable is a name for
the object itself or a reference to it.”
In an introductory text I would not start with this statement.
Better: “A variable is a place that stores a reference to an object.”
Same for your treatment of “immediate values”. This is really an
implementation detail which should be taught much later. I think it
helps understanding if one does not bring this up that early.
Actually, from a point of view of the user of the language it does not
matter at all (only for performance, but not functionality wise).

I agree. But integers is what many of us start with playing in irb. So,
I thought it was appropriate to recognize the difference between
instances of String (e.g. “abc”) and those of an Integer (e.g. 1).

“If the method were not found in String, Ruby would have followed the
superclass (sc, green arrow) links in search for the method
definition.” and “It creates a new anonymous class object and inserts
it into Foos superclass chain!”
This is not true. The chain of classes and modules found via
Module#ancestors is traversed instead. There is no need for a new
anonymous class. The only place where new classes are automatically
allocated is the singleton class of an instance.

I see. But I thought Dave T. also says something similar (in his
book) to what I wrote. The topic is about including Modules in Classes.
Even if you say that the chain returned by ancestors is traversed, where
is the reference for code for something like Mod#m? Since the same
module Mod can be included in several classes, an instance of anonymous
class for each including class seems right. But I agree, I don’t yet
know how this happens internally in the interpreter.

Also, I tried to logically explain why included module’s methods have
to
get preference over those inherited from superclasses.

I stopped reading there as I found your diagram about singleton quite
complicated and unclear.

Not a problem. I will try to clarify the diagrams. Alas, they are not
doing their job :-(. But I believe they are correct (and this stuff is
complex).

Cheers

robert

On Thu, Mar 14, 2013 at 2:42 PM, Kedar M. [email protected]
wrote:

And do you suggest that that statement is “not true”?
Yes, see above. It’s at least imprecise since “abc” does not reference
a single instance of String but it will produce a new instance every
time it is executed. See the part of my previous mail you did not
quote.

anonymous class - solely because it “seems right”? Why does it "seem
be the original superclass of Example. It then references the module
from this new class object in such a way that when you look a method up
in this class, it actually looks it up in the module, as shown in Figure
24.5, on the next page.


Is this not right?

I don’t know. But I do know that this is an implementation detail of
MRI which is invisible to the user of the language. Other than
singleton classes these new class objects cannot in any way be
observed by Ruby programs:

irb(main):001:0> a = Object.superclass.object_id
=> -1073527798
irb(main):002:0> module X end
=> nil
irb(main):003:0> class Object
irb(main):004:1> include X
irb(main):005:1> end
=> Object
irb(main):006:0> b = Object.superclass.object_id
=> -1073527798
irb(main):007:0> a == b
=> true

The information may be right or outdated but it does not necessarily
help users of the language to understand how Ruby works.

Cheers

robert

Robert is right, your wording is a bit off on this one:

  • “abc” is an instance of String *

“abc” is a shortcut (syntactic sugar?) for String.new(“abc”)

Joel P. wrote in post #1101600:

Robert is right, your wording is a bit off on this one:

  • “abc” is an instance of String *

“abc” is a shortcut (syntactic sugar?) for String.new(“abc”)

Thank you. Corrected.

On Thu, Mar 14, 2013 at 3:14 PM, Kedar M. [email protected]
wrote:

Robert K. wrote in post #1101602:

On Thu, Mar 14, 2013 at 2:42 PM, Kedar M. [email protected]
wrote:

module Mod, Anonclass is not returned when you do Someclass.superclass.

But if methods were only to be defined on class objects, I am not sure
where the included module methods would come from without disturbing
inheritance chain of classes.

You could model it like this: every class has a list of included
modules which is initially empty. Every time a module is included
which is not included in this class or any super class it is prepended
to the list. Method lookup starts with the class itself, then
proceeds through the list of modules of this class and then proceeds
in the same way in the superclass; the process is stopped when the
first matching method is found. If not matching method is found the
lookup process starts again with name “method_missing”. (That process
with end in class BasicObject which has a definition of
#method_missing.)

Any MRI experts – how does it really happen?
And how about JRuby/Rubinius?

You can look it up in the implementation - it’s OSS.

Kind regards

robert

Robert K. wrote in post #1101612:

On Thu, Mar 14, 2013 at 3:14 PM, Kedar M. [email protected]
wrote:

Robert K. wrote in post #1101602:

On Thu, Mar 14, 2013 at 2:42 PM, Kedar M. [email protected]
wrote:

module Mod, Anonclass is not returned when you do Someclass.superclass.

But if methods were only to be defined on class objects, I am not sure
where the included module methods would come from without disturbing
inheritance chain of classes.

You could model it like this: every class has a list of included
modules which is initially empty. Every time a module is included
which is not included in this class or any super class it is prepended
to the list. Method lookup starts with the class itself, then
proceeds through the list of modules of this class and then proceeds
in the same way in the superclass; the process is stopped when the
first matching method is found. If not matching method is found the
lookup process starts again with name “method_missing”. (That process
with end in class BasicObject which has a definition of
#method_missing.)

But … I thought a decision had already been made – any method
definition is to occur only on a class object. If that assumption is not
true and method definitions can occur on modules, then yes, other
implementation choices exist.

Any MRI experts – how does it really happen?
And how about JRuby/Rubinius?

You can look it up in the implementation - it’s OSS.

Thanks! I guess I will need to do that.

Kind regards

robert

On Thu, Mar 14, 2013 at 4:07 PM, Kedar M. [email protected]
wrote:

But if methods were only to be defined on class objects, I am not sure
lookup process starts again with name “method_missing”. (That process
with end in class BasicObject which has a definition of
#method_missing.)

But … I thought a decision had already been made – any method
definition is to occur only on a class object. If that assumption is not
true and method definitions can occur on modules, then yes, other
implementation choices exist.

They do - from perspective of a language user. I would try to
cleanly separate the language from implementation details. That will
make understanding for newcomers much easier.

Cheers

robert

Robert K. wrote in post #1101602:

On Thu, Mar 14, 2013 at 2:42 PM, Kedar M. [email protected]
wrote:

And do you suggest that that statement is “not true”?
Yes, see above. It’s at least imprecise since “abc” does not reference
a single instance of String but it will produce a new instance every
time it is executed. See the part of my previous mail you did not
quote.

OK. Clarified. Thank you.

anonymous class - solely because it “seems right”? Why does it "seem
be the original superclass of Example. It then references the module
from this new class object in such a way that when you look a method up
in this class, it actually looks it up in the module, as shown in Figure
24.5, on the next page.


Is this not right?

I don’t know. But I do know that this is an implementation detail of
MRI which is invisible to the user of the language. Other than
singleton classes these new class objects cannot in any way be
observed by Ruby programs:

irb(main):001:0> a = Object.superclass.object_id
=> -1073527798
irb(main):002:0> module X end
=> nil
irb(main):003:0> class Object
irb(main):004:1> include X
irb(main):005:1> end
=> Object
irb(main):006:0> b = Object.superclass.object_id
=> -1073527798
irb(main):007:0> a == b
=> true

The information may be right or outdated but it does not necessarily
help users of the language to understand how Ruby works.

My observation too has been that this so-called anonymous class is not
to be found via the :superclass method and I have already clarified that
in the document as:


This diagram is not entirely accurate because although Anonclass appears
to become superclass of Someclass, just by the virtue of inclusion of
module Mod, Anonclass is not returned when you do Someclass.superclass.

But if methods were only to be defined on class objects, I am not sure
where the included module methods would come from without disturbing
inheritance chain of classes.

Any MRI experts – how does it really happen?
And how about JRuby/Rubinius?