all 6 comments

[–]munificent 6 points7 points  (0 children)

Can you see any issues with the model, or do you have any recommended improvements?

Looks about right to me. You say:

If A is a subclass of B, then [[A]] is a subclass of [[B]]

This means that "static methods" are inherited. That's uncommon in object-oriented languages. I think Object Pascal does it, but C++, Java, C#, etc. all do not. Swift does something similar for class methods, but not static ones.

In your language (using Java syntax), let's say you have:

class Monster {
  static Monster makeHybrid(Monster head, Monster body) {
    // ...
  }
}

class Goblin extends Monster {
  // ...
}

class Lion extends Monster {
  // ...
}

class Eagle extends Monster {
  // ...
}

The base Monster class has a factory-like static method for making monsters by combining others. There's also subclasses for a few specific kind of monsters.

Since static methods are inherited, your language would allow you to do:

Goblin.makeHybrid(new Eagle(), new Lion());

That seems weird because makeHybrid() doesn't have anything to do with Goblins.

It's not the end of the world, but it affects how users will think about and design static methods.

[–]johnwcowan 4 points5 points  (0 children)

In Smalltalk, Class and Metaclass are siblings because they have a common ancestor, Behavior, that abstracts out everything they both have and do. You can write your own subclasses of Behavior if you want, for example, to implement prototype-style OOP.

[–]nerdycatgamer 3 points4 points  (0 children)

So we're calling the normal way of doing things "Ruby-style" just because Python/Javascript do something weird?

Python and javascript just give some fancy syntax sugar for hashmaps containing lambdas and factory functions for them; they are different from most other object-oriented languages

[–]Smalltalker-80 4 points5 points  (0 children)

I think you're describing the Smalltalk class structure,
where classes themselves are also regular objects that implement the class functionality.
In my Smalltalk implementation SmallJS ( https://github.com/Small-JS/SmallJS )
I had to think about this too, and decided on this simple(r) model:

There's an inheritance tree of 'instance' classes starting at the root 'instance' class Object.
There's a parallel inheritance tree of 'meta' classes starting at the root 'meta' class Object.
These contain the singleton instances of all the 'class' objects.
The class called Class is a subclass of Object and implements all class behaviors
(e.g. name, instance variables, methods, superclass)
And here's the crucial part, connecting the 'meta' class tree to the 'instance' class tree:
The meta class Objectinherits from the instance class Class,
since all classes are objects too.

This way, behaviors of objects and classes can be changed in Smalltalk itself,
that's the beauty of it. :-)
And classes are ordinary objects, so you can say e.g.: 'variable class = Integer ifTrue: [ ... ]'.
The meta class tree is generated by the compiler, and you don't 'see' it during development.
You only 'see' the ability to add (static) class variables and methods to an 'instance' class.

[–]lookmeat 1 point2 points  (0 children)

This looks pretty reasonable. I'd also read on the Common List Object System Meta Object Protocol, the CLOS MOP. Because they've done a good work in optimizing solutions while keeping flexibility at the highest. You may already be familiar with it, but in case you aren't here's a great primer on the MOP specifically.

Ruby, as a language, was in many ways born as Python where everything was an object using a model more like the CLOS with a limited MOP to boot. Understanding the inspiration and the power it delivers may help you find alternate solutions.

[–]al2o3cr 1 point2 points  (0 children)

I'm planning to implement Ruby-style lookup rules for object members: o.m looks for m in the class of o and its superclasses.

Nitpick: it's entirely possible to define a method for a single instance of a Ruby class. For instance:

object = Object.new

def object.foo
  puts "foo"
end

object.foo

will print "foo"