Finding a "safety syntax" for classes

Allen Wirfs-Brock allen at wirfs-brock.com
Wed Mar 21 10:54:12 PDT 2012


On Mar 20, 2012, at 10:32 PM, Mark S. Miller wrote:

> I have always been suspicious of static method inheritance. Smalltalk-76 did not have it. Smalltalk-80 did. Although I only ever had hands on with Smalltalk-80, I always felt that Smalltalk-76 had this one right. I know other smalltalkers disagree.

First off, it is wrong to call these "static methods".  There is nothing static about them.  We are simply talking about regular dynamic properties of a function object.  By using the term "static" you are making an association with a different concept that comes statically typed languages where "classes" are not first class objects.  JavaScript is not that kind of language and it is wrong to draw inferences from them.  I suggest that we call these "class properties" or "function properties".

Rather than using Java/C++ for a model and  terminology  for classes we should be looking at successful class-based dynamic OO languages.

Smalltalk-80 added them because they discovered that having a single set of behaviors for all class objects was too constraining. 
Ruby also supports class methods with inheritance.  [1] seems like a reasonable tutorial on using class methos in Ruby. 

[1] http://www.rubyfleebie.com/understanding-class-methods-in-ruby/ 


> 
> I think in a de-novo language like Dart or Smalltalk at the time, they are at least plausible. So I find it interesting that Dart chose to avoid them. For JS, I think they are disastrous because of "this" confusions. Normally, when a JS method is "static", what we implicitly mean is that it is to be found on a constructor function, and that the method does not depend on its this-binding. For static method inheritance to make sense, many static methods would instead be written to be this-sensitive. This will cause common usage patterns to break.

There is no reason for this confusion.  It think you must be coming from thinking about class methods as "static".  Classes (functions) are just objects and object have properties some of which have function values.  We call such properties methods.  When a method is invoked on an object (eg, foo.method())  the this minding is the target object of the invocation (eg, foo).  That is true regardless of whether foo is an "instance", or a function, or a class.  It is simply how object-oriented invocation works. 

I don't know where you got the "and that method does not depend on its this-binding" from.  It certainly isn't a given and it isn't the convention in dynamic class based languages.

If you define 

    Array.from = function(collection) {
          ...
          this
          ...
    }

and call it 
      Array.from(someCollection) 

withi the activation of that function the value of |this| is going to be Array.  There is no way around it. There are plenty of good reasons to use this.  Consider a naive implementation of this function

    Array.from = function(collection) {
          let a = new Array;
          for (let v of collection) a.push(v);
          return a;
    }

I say this is naive because it has a significant problem.  Array methods are generally "generic" so what if we just assume that the from method is also generic and installed in on some other "class":

   MyArrayLike = Array.from;
   MyArrayLike.prototype = Array.prototype.push;  //push really is generic and will work as a method on any object

What do we get if we then say:

    MyArrayLIke.from(myCollection) instanceof MyCollection     //expect true, but get false

This wouldn't be the case if we had properly coded from using this:

    Array.from = function(collection) {
          let a = new this;   // <=============  this, not Array
          for (let v of collection) a.push(v);
          return a;
    }

This same idea applies if instead of copying a reference to the from function we had inherited it directly from Array:

    class SpecializedArray extends Array { ...};

We should be able to say:

     let s = SpecializedArray.from([1,2,3,4,5]);

an get an instance of SpecializedArray.  Referencing this in class methods is the key to making this all work.

> 
> For JS, because of its this-binding rules and the programming patterns that have adapted to these rules,

JS this binding rules are absolutely no different from Smalltalk, Ruby, or most any other OO language.  The only thing that is different about JS is that it makes it (too) easy to  extract a method as a function without an object association and then to invoke that function with an arbitrary (or default) this value (as if, the function was installed as a method on the this value object).  I don't see how that latter fact has any relevance to this discussion.   If you extract methods you need to know what requirements they impose upon their this value.  This applies whether the method was defined as an instance method, a class method, or just as a naked function.

> I believe it is too late for static inheritance. But even if it weren't, I suspect it's a bad idea anyway.

I'm quite certain that class-side inheritance is a good idea for dynamic class based OO languages with inheritance.   It has proven utility.  There may be things about that kind of language that an individual might not like.  They might object to dynamic, or class-based, or OO, or inheritance.  But if you have that combination, inheritable class methods make a lot of sense.

Allen

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20120321/b5295a85/attachment-0001.html>


More information about the es-discuss mailing list