The Class/Object Paradox Confusion

The Class/Object Paradox confusion

You can see the problem in this diagram:

Ruby Method Lookup Flow

(source: phrogz.net)

All object instances inherit from Object. All classes are objects, and Class is a class, therefore Class is an object. However, object instances inherit from their class, and Object is an instance of the Class class, therefore Object itself gets methods from Class.

As you can see in the diagram, however, there isn't a circular lookup loop, because there are two different inheritance 'parts' to every class: the instance methods and the 'class' methods. In the end, the lookup path is sane.

N.B.: This diagram reflects Ruby 1.8, and thus does not include the core BasicObject class introduced in Ruby 1.9.

Ruby metaclass confusion

how do this work

Easy: it doesn't. Not in Ruby, anyway.

Just like in most other languages, there are some core entities that are simply assumed to exist. They fall from the sky, materialize out of thin air, magically appear.

In Ruby, some of those magic things are:

  • Object doesn't have a superclass, but you cannot define a class with no superclass, the implicit direct superclass is always Object. [Note: there may be implementation-defined superclasses of Object, but eventually, there will be one which doesn't have a superclass.]
  • Object is an instance of Class, which is a subclass of Object (which means that indirectly Object is an instance of Object itself)
  • Class is a subclass of Module, which is an instance of Class
  • Class is an instance of Class

None of these things can be explained in Ruby.

BasicObject, Object, Module and Class all need to spring into existence at the same time because they have circular dependencies.

Just because this relationship cannot be expressed in Ruby code, doesn't mean the Ruby Language Specification can't say it has to be so. It's up to the implementor to figure out a way to do this. After all, the Ruby implementation has a level of access to the objects that you as a programmer don't have.

For example, the Ruby implementation could first create BasicObject, setting both its superclass pointer and its class pointer to null.

Then, it creates Object, setting its superclass pointer to BasicObject and its class pointer to null.

Next, it creates Module, setting its superclass pointer to Object and its class pointer to null.

Lastly, it creates Class, setting its superclass pointer to Module and its class pointer to null.

Now, we can overwrite BasicObject's, Object's, Module's, and Class's class pointer to point to Class, and we're done.

This is easy to do from outside the system, it just looks weird from the inside.

Once they do exist, however, it is perfectly possible to implement most of their behavior in plain Ruby. You only need very barebones versions of those classes, thanks to Ruby's open classes, you can add any missing functionality at a later time.

In your example, the class Class is not creating a new class named Class, it is reopening the existing class Class, which was given to us by the runtime environment.

So, it is perfectly possible to explain the default behavior of Class#new in plain Ruby:

class Class
def new(*args, &block)
obj = allocate # another magic thing that cannot be explained in Ruby
obj.initialize(*args, &block)
return obj
end
end

[Note: actually, initialize is private, so you need to use obj.send(:initialize, *args, &block) to circumvent the access restriction.]

BTW: Class#allocate is another one of those magic things. It allocates a new empty object in Ruby's object space, which is something that cannot be done in Ruby. So, Class#allocate is something that has to be provided by the runtime system as well.

How the BasicObject, Object, and Kernel interact each other?

You are confusing two meanings of "is": "instance of" and "subclass of".

1) Regarding subclass relation:

  • Class is a subclass of Module.
  • Module is a subclass of Object.
  • Object is a subclass of BasicObject.

And due to transitivity, Class is a subclass of Object and of BasicObject, and Module is a subclass of BasicObject. But there is no circularity here. For example, BasicObject is not a subclass of Class, Module, or Object.

2) Regarding instantiation relation:

  • Class is an instance of Class (as well as (kind) of Module, Object, BasicObject).
  • Module is an instance of Class (as well as (kind) of Module, Object, BasicObject).
  • Object is an instance of Class (as well as (kind) of Module, Object, BasicObject).
  • BasicObject is an instance of Class (as well as (kind) of Module, Object, BasicObject).

But there is no circularity in instantiation relation. Circularity is a notion defined on transitive relations. For example, If A → B and B → C, then it follows that A → C due to transitivity, and if it is C → A as well, then there is circularity. But instantiation relation is not transitive. "A is an instance of B" and "B is an instance of C" does not mean that "A is an instance of C". So circularity cannot be defined on instantiation relation in a non-trivial way.

Can someone explain the Class.superclass.class.superclass paradox?

TL;DR: Module is the superclass of Class. Module is an instance of Class.


Let me try to explain it more clearly. Please forgive my handwritten drawings - I don't have any fancy drawing software.

Every class in Ruby has 1 superclass*.

Sample Image

*Except for BasicObject, which doesn't have a superclass.

Read the above graphic like this: The superclass of Float is Numeric. The superclass of Numeric is Object, etc...

When you instantiate an object, the object will be an instance of some class. For example, "Nathan" is an instance of the String class. So is "Joe" or "John". 1 is an instance of the Fixnum class, as are 2, 3, 4, etc...

Sample Image

Read the above graphic like this: "Joe" is an instance of String. 1 is an instance of Fixnum, etc...

Well, in Ruby, unlike in most other languages, Class is a just another class, and it can be instantiated, too, just like Fixnum or String.

Sample Image

Read the above graphic like this: 0.01 is an instance of Float. String is an instance of Class, etc...

Realize that Fixnum is an instance of Class, just like "Nathan" is an instance of String. Just like "John" is an instance of String, Float is just an instance of Class. Every class is just an an instance of Class, even Class itself!

Whenever you write a new class in your app, you are just instantiating a new object whose class is Class, just like Hash.new instantiates a new Hash, or "Nathan" instantiates a new String.

# By running this, you will be instantiating a new Class, and 
# it will be named Post
class Post < ActiveRecord::Base
end

# Here is another perfectly valid way to write the above code:
Post = Class.new(ActiveRecord::Base)

# you can even instantiate a Class without giving it an explicit name:
x = Class.new(ActiveRecord::Base)

# and since your new things are classes, they can be instantiated
obj1 = Post.new
obj2 = x.new

Furthermore, Module is just another instance of Class. Whenever you write a new module in your app, you are just instantiating a new Module.

# this will instantiate a new Module, and assign it to Foo
module Foo
end

# Here is another perfectly valid way to write the above code:
Foo = Module.new

# you can even instantiate a Module without giving it an explicit name.
m = Module.new

An aside: A Module is just a collection of methods and constants. Classes are also a collection of methods and constants, but with the added functionality of being able to be instantiated. A module cannot be instantiated. That is, m.new will not work.

So, referring back to the top graphic, your question can be answered directly:

So a class's parent is module, but module is a class?

You can see from the top graphic: Module is the superclass of Class.

From the bottom graphic: Module is an instance of Class.

Understanding class and object in scala

I'll try to explain what a Scala object is from the perspective of someone who knows Java.

In Java, you can define "normal" class members and static class members. When something (for example a member variable) is static in Java, then there's only one instance of that member variable, which is shared by all instances of the class.

In Scala, there is no static. Compared to Java: whatever you would make static in Java, you would put in an object in Scala.

A Scala object is a singleton - there's only a single instance of it, just like static members in Java of which there's only a single instance.

I hope that makes it a little bit more clear what a Scala object is exactly.

A Scala object can extend classes or traits just like any other class or trait, so that it inherits whatever was defined in the class or trait that it extends. There's really no reason why this should not be possible.

Note that if you have a class and an object with the same name, then those two belong together - they can see each other's private members. The object is called the companion object of the class.

Note that this does not mean that the object is an instance of the class. It is not - it is a separate thing that stands beside the class. Maybe your confusion about the class and object extending different traits comes from a misunderstanding about that point.

Why does python confuse my packages for modules

In Java imports are just syntactic sugar (no really). In python they are actual statements and they are resolved based on complex rules involving the sys.path variable and the current working directory. The correct way to run a python script (aka module) that resides in a package is:

$ C://path//to//python//interpreter.exe -m packagename.modulename

So in your case

$ cd "C:\Users\Ben\VsCode\python\"
$ C://path//to//python//interpreter.exe -m classgenerator.parsing.class_dict

This way the relative imports are resolved correctly as "C:\Users\Ben\VsCode\python" is automatically added to the sys.path and python scans it a finds the package classgenerator and the subpackage parsing



Related Topics



Leave a reply



Submit