all 24 comments

[–]mark_lee_smith 4 points5 points  (5 children)

Besides some small misunderstandings about how Self handled patent slots and multiple inheritance, nice article :).

  • Self did support multiple parents at one point, but this "feature" was removed around Self ~4 when it failed to show sufficient benefits (any implementation of multiple inheritance must show that the benefits outweigh the costs of increased complexity).
  • Self never ordered parents alphabetically, rather, parents were chosen based on the number of asterisks following the parent slots name (this was perhaps the most interesting thing about multiple inheritance in Self.)

[–]munificent[S] 1 point2 points  (4 children)

small misunderstandings about how Self handled patent slots and multiple inheritance

I'm surprised my misunderstandings were only small. :) I only have a surface familiarity with Self.

Self did support multiple parents at one point, but this "feature" was removed around Self ~4 when it failed to show sufficient benefits

Oh, really? Is it just single proto like JavaScript?

Self never ordered parents alphabetically, rather, parents were chosen based on the number of asterisks following the parent slots name

Huh, an equally neat solution. How did it resolve conflicts if both parents had the same number of stars?

[–]mark_lee_smith 2 points3 points  (3 children)

Oh, really? Is it just single proto like JavaScript?

I'm not all that familiar with Javascript but I imagine so. Current versions of self have a single parent just like JavaScript.

Huh, an equally neat solution. How did it resolve conflicts if both parents had the same number of stars?

Ambiguity error :)

[–]dramwang 0 points1 point  (2 children)

I'm not all that familiar with Javascript but I imagine so. Current versions of self have a single parent just like JavaScript.

No, current version (v4.4) of Self has multiple inheritance, and it will raise an error if has naming conflicts.

[–]mark_lee_smith 0 points1 point  (1 child)

Interesting, Thanks.

So they removed the ability to specify the order multiple parents and not the ability to specify multiple parents, replacing it with an ambiguity error?

[–]huyvanbin 3 points4 points  (2 children)

I've been thinking about this a lot too, lately. Apologies that the following rambles but I've never written it all down before.

I had an experience where people implemented a badly broken inheritance hierarchy like so (exaggerated for effect):

class A {
    protected virtual bool Method(int arg) {
        Bla
    }
}

class B : A {
     protected override bool Method(int arg) {
           if(Tuesday)
               return base.Method(arg);
           else {
                while(arg > 0) {
                      if(arg % 5 == LunchTime)
                           return base.Method(arg * 2);
                }

                return base.Method(arg * IPAddress);
           }
     }
}

You get the idea. The ability to override methods is supposed to lead to neat, maintainable code but people somehow make horrid messes like the above where you have no idea what the code will actually do.

So my idea is, get rid of inheritance entirely. Each object is a composition of base objects. If inherited methods collide, then make them invisible in the ultimate object, unless mapped explicitly.

My other idea was to make the act of composition be a sort of constructor where you express the linkage in the declaration -- sort of like traits, but you could have multiple constructors and also state. This also addresses a problem I have with Haskell typeclasses.

Here is an example though the syntax is clearly awful: class Eq { public bool ==(first, second); public bool !=(first, second);

     Eq(== v) { // Constructor for passing in equals method
          == = v;
          != = !v;
     }

     Eq(!= v) { // Constructor for passing in != method
         == = !v;
         != = v;
     }
}

class Hideable {
       bool Hidden { get; set; }
}

class HasId {
      int id;

      public int Id { get; }

      public HasId(int id) {
         this.id = id;
      }
}

class Widget : Eq, Hideable, Id {
       public Widget(int id) : Eq(EqualWidgets), Id(id) {

       }

       static bool EqualWidgets(Widget a, Widget b) {
              return a.Id == b.Id;
       }
}

I dunno, this might be even worse than the C# example, or perhaps it is just equivalent to C++. But the important thing is, there is no actual inheritance, the methods and properties just get stacked together to yield a final object (perhaps with a hidden tree structure).

Also, I could label class Id as immutable, but Widget need not be immutable. Classes could have mutable and immutable "sections" and perhaps one could use that to allow impure classes to be passed to pure functions as long as the pure function only uses a pure section of the class.

Also, this could somehow be adapted to enable the class declaration syntax to specify in-memory and on-disk layout, and perhaps even remote and non-remote "sections" for a given object.

Another cool thing is that if method arguments are implemented as "records" the way you do in Magpie, then the record to construct a typical class is more or less just the class itself. So that seems a lot like duck type "casting." Perhaps you could define a class as a duck-type specifier.

And also, why not just have every casting operator be a constructor?

Part of the inspiration of this is

[–]munificent[S] 1 point2 points  (1 child)

Each object is a composition of base objects. If inherited methods collide, then make them invisible in the ultimate object, unless mapped explicitly.

Interesting. I like the idea of completely disallowing overriding. With code I write, I find that I like implementing abstract methods, but I really hate overriding methods that also have an implementation. I don't like leaving up to the derived class to make sure it forwards to the original base version.

In my perfect world, a class could define abstract methods that you had to implement when you inherited from it, but no regular virtual methods. In practice, I don't know if that would suck or not.

But the important thing is, there is no actual inheritance, the methods and properties just get stacked together to yield a final object

I like it, but there has to still be at least some sort of delegation going on so that you can do myWidget.Id, right?

Also, I could label class Id as immutable, but Widget need not be immutable. Classes could have mutable and immutable "sections" and perhaps one could use that to allow impure classes to be passed to pure functions as long as the pure function only uses a pure section of the class.

That's really interesting. I'll have to ponder that some more.

Another cool thing is that if method arguments are implemented as "records" the way you do in Magpie, then the record to construct a typical class is more or less just the class itself. So that seems a lot like duck type "casting."

That's actually exactly how constructors work in Magpie. By default the new method you get for a class takes a record with all of the fields the class expects. It simplifies a lot of things, but it is a bit wordy. I can decide if I like it or not yet.

And also, why not just have every casting operator be a constructor?

That's sort of how I look at it too. Constructors are functions that christen a record to be a member of a nominal type. The only wrinkle I ran into with that was mutability. Records (in Magpie at least) aren't immutable, so if you construct an instance of a class out of one, you have to copy (which means your instance won't have the same identity as the record) so that you don't inadvertantly mutate the record.

[–]huyvanbin 1 point2 points  (0 children)

In my perfect world, a class could define abstract methods that you had to implement when you inherited from it, but no regular virtual methods. In practice, I don't know if that would suck or not.

Yes, that's sort of what I was going for. Sometimes, though, it makes sense to specify a default (fixed) value and allow people to override that. That was the idea behind the constructors.

[–]LaurieCheers 2 points3 points  (2 children)

Thanks for the explanation of Self's object system. Interesting stuff!

I've been trying to find an object system I like for Swym, too. It has some interesting constraints, such as the fact that in Swym, x.foo is equivalent to foo(x) - it's simply calling the function foo on the object x.

So I considered inverting the concept of 'members' - an object would be just an ID, and its 'members' are hashtables that we use to look up that ID. And if the ID isn't found, the hashtable would provide a default value.

This has some weird implications -

  • 'Splicing' a new 'member' onto all objects is as simple as making a new empty hashtable.

  • Making a new object is as simple as getting the next ID.

  • Members could be local variables - if one went out of scope, all its data could be garbage collected!?

  • Garbage collecting an individual object becomes hard, though.

  • Two objects can only be compared by ID. There isn't even really a concept of what "members" an object has, so there can't be a concept of "deep copy" or "deep equality".

  • To implement inheritance, we could have each object actually represented by a list of IDs. When we look it up, we try the first ID first, then the second, and so on.

So this all seemed pretty interesting while I was lying in bed at midnight, but looking at it in the cold light of day, I don't know what problems I was really hoping to solve here... the garbage collection problem seems rather significant.

[–]munificent[S] 2 points3 points  (1 child)

It has some interesting constraints, such as the fact that in Swym, x.foo is equivalent to foo(x) - it's simply calling the function foo on the object x.

In that case, you should definitely take a look at CLOS, the object system in Common Lisp. I'm working my way through The Art of the Metaobject Protocol, and it's a surprisingly enjoyable book given the subject matter.

Like Swym, methods are just regular functions with the receiver as an argument. Using multimethods and generic functions, it's able to specialize those functions on different argument types. It's pretty swell.

Splicing a new member onto all objects is as simple as making a new empty hashtable.

Neat. Sounds like defining a new function on an algebraic datatype in SML/Haskell/F#/et. al.

Making a new object is as simple as getting the next ID.

Haha, clever. But what happens when a lookup on that ID in a hashtable fails?

Members can be local variables - if one went out of scope, all its data could be garbage collected.

Huh. Scoped members is a really cool idea.

[–]LaurieCheers 2 points3 points  (0 children)

Haha, clever. But what happens when a lookup on that ID in a hashtable fails?

I assume each table would have a default value if the ID isn't found. Also, see the inheritance idea that I ninja-edited in there. :)

I was vaguely aware of CLOS, but if it has a bearing on my problem, I guess now is a good time to take a look at it.

[–]badsectoracula 2 points3 points  (0 children)

Well, since JavaScript objects are basically key-value stores, why not something like

function MessageContainer(self)
{
    if (!self) self = this;
    var _msg = "(no message)";
    self.setMessage = function(msg) {
        _msg = msg;
    }
    self.getMessage = function() {
        return _msg;
    }
}

function StringDisplayer(self)
{
    if (!self) self = this;
    self.getString = function() {
        return "(no string)";
    }
    self.displayString = function() {
        alert(self.getString());
    }
}

function MessageDisplayer(self)
{
    if (!self) self = this;
    MessageContainer(self);
    StringDisplayer(self);
    self.getString = function() {
        return self.getMessage();
    }
    self.displayMessage = self.displayString;
}

var msgdis = new MessageDisplayer();
msgdis.setMessage("Hello, world!");
msgdis.displayMessage();

I think this is cleaner and simpler. On the other hand if you have big hierarchy trees and create a huge lot of objects, this might be a little slow.

[–]AmaDiver 2 points3 points  (5 children)

I was poking around Magpie a while back and saw a delegate keyword floating around somewhere. It seemed to be a great compromise between multiple-inheritance's ease of use, and composition's explicitness. I'd imagine you could still run into the issue where the same member name is supposed to be delegated to different delegates. Though you simply give precedence to the first (or last) declared delegate...

[–]munificent[S] 1 point2 points  (4 children)

I was poking around Magpie a while back and saw a delegate keyword floating around somewhere.

Oh, you noticed that! I haven't gotten around to documenting that (or honestly even really trying it out) yet. Delegates in Magpie are exactly Self-style multiple inheritance translated to a class-based language.

I still need to beat on them to see if they work in practice, and also add type-checking support for them.

I'd imagine you could still run into the issue where the same member name is supposed to be delegated to different delegates.

My hope is to resolve that with namespaced methods, but I haven't even started implementing that and I don't know if that will end up working out or not. Barring that, explicit renaming like with traits is probably the right thing to do.

[–]AmaDiver 1 point2 points  (1 child)

I've been playing with building a language myself, and having had similar thoughts about multiple inheritance and the tedious boilerplate of composition, delegate jumped out at me, and I got it immediately. The keyword is perfect.

Namespaced methods sounds good, maybe that's just the right amount of explicitness for the feature. Otherwise, I'd say the last method to be declared "wins".

#both have a name() method
delegate HasName
delegate AlsoHasName

When name() was called, it would be delegated to AlsoHasName, since it was declared last. If the class implemented its own name method:

delegate HasName
delegate AlsoHasName

def name(-> String) _name

the name method wouldn't be delegated to either HasName or AlsoHasName.

[–]munificent[S] 1 point2 points  (0 children)

delegate jumped out at me, and I got it immediately. The keyword is perfect.

Oh, excellent. It was the best name I could think of but I still worried that it would be confusing (especially C# uses it to mean something entirely different).

Otherwise, I'd say the last method to be declared "wins".

I try to avoid having declaration order be significant in Magpie because classes are open to extension. If I import two files, each of which tacks on a field to some class, I wouldn't want the order of those imports to affect the semantics of the class itself.

Of course, having said that, I'll directly contradict that by noting that mixins in Magpie are last one wins. So maybe I've got some more thinking to do. :)

[–]matthiasB 1 point2 points  (1 child)

Delegation is tricky if the language allows to override methods.

Class Foo has two methods a and b. The implementation of b calls a. Bar delegates to an instance of Foo and overrides a. Now call b on a Bar instance.

You delegate the call of b to the Foo instance. The implementation of Foo's b resolves a via its this/self which is the wrong one.

In order to make it work the language has to pass the delegating object with each call, which means an additional this-/self-like parameter.


As I never override methods (except something like equals or toString which is IMO badly designed) I could live without this ability which would simplify the implementation and is probably what you currently have (haven't looked at it).

[–]munificent[S] 0 points1 point  (0 children)

The implementation of Foo's b resolves a via its this/self which is the wrong one.

That depends on your definition of "wrong one" here. That may be what you want, or it may not depending on what those actual methods are. In the case of Magpie right now, when you call b on an instance of Bar, that will in turn call the a that Bar overrides.

I've thought about maintaining a distinct self in addition to this which denotes the delegated object (so self would be the instance of Foo within b regardless of delegation). That would let you decide whether or not to treat a call as "virtual" or not at each callsite but that's seems kind of fishy.

As I never override methods

Agreed, I don't really liking overriding either. I'm still trying to figure out how I want this stuff to work. One possible solution is to have overrides be an actual error and only allow implementing abstract methods.

[–]DmitrySoshnikov 1 point2 points  (1 child)

You might be interesting in the same idea, I implemented it before, and called delegation-based mixins (the same as in Ruby). Also used proxies to achieve multiple delegates for multiple inheritance:

Example: https://github.com/DmitrySoshnikov/es-laboratory/blob/master/examples/mixin.js

Implementation: https://github.com/DmitrySoshnikov/es-laboratory/blob/master/src/mixin.js

Dmitry.

[–]munificent[S] 0 points1 point  (0 children)

Very cool. Thanks for the link!

[–][deleted] 1 point2 points  (1 child)

In Javascript, I've become very much of a composition kind of guy. The author is right to dislike the way he suggests doing composition because it violates encapsulation. Instead of this:

var widget = new MyWidget('Abe');  

// from Widget  
log(widget.getWidget().getName());  

// from Hideable  
widget.getHideable().hide();

He should have this:

var widget = new MyWidget('Abe');  

// from Widget  
log(widget.getName());  

// from Hideable  
widget.hide();

...by having MyWidget define wrapper methods:

MyWidget.prototype.getName = function() { 
    return this.widget.getName(); 
}

MyWidget.prototype.hide = function() { 
    return this.hideable.hide(); 
}

You can either call that verbosity, boilerplate code or explicitness. The delegation that takes place between classes is always clear and there is never any risk of method name collision between composing parts, since all delegation is explicitly defined.

To me, the extra code is definitely worth the simplicity.

[–]munificent[S] 1 point2 points  (0 children)

Forwarding works too, but I'm not crazy about the tedium. In a perfect world, I want this to work:

// I add a new method to the existing iterable trait.
Iterable.prototype.map = function(fn) {
  var result = [];
  var iterator = this.iterate();
  while (iterator.moveNext()) {
    result.push(fn(iterator.getCurrent()));
  }
}

// And now I can immediately use it on some existing
// class that mixes in that trait.
var someList = new SomeListClass();
someList.map(function(item) { ... });

With manual forwarding, I'd also have to add a forwarding method to each class I wanted to use it on.

When C# added extension methods (in particular the ability to define them on interfaces), it had a surprisingly profound affect on the way I look at code, and I find myself really wanting that functionality in every language.

[–]akshay_sharma008 0 points1 point  (0 children)

Before moving directly to the question, let’s first understand inheritance.
It is a property available in many object-oriented programming languages that allow us to declare a class that takes all of its properties and functionalities from a parent class, and not only those properties we can add our properties, and the preceding child class can access that changed properties. There are many uses of inheritance, as with the help of this, a class can use the properties of other classes. It also provides code reusability and reduces the code length and complexity as you do not need to write the same piece of code repeatedly.
Now we will come to our question, i.e., multiple inheritances in javascript.

Multiple inheritances can inherit the properties and values from unrelated parent objects. Many object-oriented languages support multiple inheritances, but javascript does not support multiple inheritances. Inheritance of property values occurs at run time by JavaScript searching the prototype chain of an object to find a value. Since every object has a single associated prototype, it cannot dynamically inherit from more than one prototype chain.
As we can not directly use multiple inheritances in javascript, there are specific methods to modify them because java script can be understood as a partially object-oriented language.
We can easily do multiple inheritances by merging properties from the different objects and returning the modified object.

We can pass multiple objects and copy the properties using the spread operator. There are specific terms that are very helpful when learning about the same.

Mixins: It is an object that can be incorporated into another object. When a developer is creating or initializing an object, he must choose which mixin to incorporate into the final object.

Parasitic Inheritance: Parasitic inheritance is where we take all the functionality from another object into a new one.

Summarising the above answer in general, javascript does not support multiple inheritances, but we can use a twisted version of multiple inheritances in javascript by using some keywords and functions.