Interesting, I didn’t know this!
It seems like .class
in only intended for instances and .superclass
is only meant for classes; in fact, calling the latter on a class instance throws an error. I’m wondering if calling .class
on a Class
instance shouldn’t throw an error as well…
I’m not sure of the reason why .class
navigates from an instance of a class to its class, but from the class to its meta-class… but that’s what it does.
I think it kind of makes sense. SinOsc
is not an instance of PureUGen
, it only inherits from it. It is, however, an instance of Meta_SinOsc
which in turn is an instance of Class
. These are two different relationships, that’s why we have two different methods (class
and superclass
).
Now, here’s comes the baffling thing: Class
is a subclass of Object
. This means objects are instances of classes, but classes themselves are also objects. It’s a classic condundrum in many object oriented languages.
For Python, see for example metaclass - what is the difference between type class and object class in python - Stack Overflow.
Similarly, in C# objects are instance of classes – with Object
Object Class (System) | Microsoft Learn) being the root class – but classes themselves are also objects and inherit from Object
, see Type Class (System) | Microsoft Learn.
In fact, these two relationships form two hierarchies:
- class inheritance (with
.superclass
):
[instance] -> SinOsc -> PureUGen -> UGen -> Object
- classes as objects (with
.class
):
SinOsc -> Meta_SinOsc -> Class -> Meta_Class -> Class -> Meta-Class -> ad inf.
We can also see the same two relationships with Class
itself:
Class -> Object
(with .superclass
)
Class -> Class -> Meta_Class -> Class -> Meta-Class -> ad inf.
I’m not even trying to resolve this conundrum, I’m already feeling dizzy. 
In a prototypical language like Lua or JS there is indeed a symmetric relationship between objects and classes and superclasses.
For example, that’s how you get the “superclass” of an instance in JS:
Object.getPrototypeOf(Object.getPrototypeOf(foo));
You call getPrototypeOf
to get the “class” (= the prototype), then a second time to get the “superclass” (= the prototype of the prototype).
Similarily in Lua:
getmetatable(getmetatable(obj));
BTW, that’s what I love so much about Lua: it is very easy to reason about and there is very little magic going on 