"Syntax for Efficient Traits" is now ready for discussion (was: Classes as Sugar is...)

Dmitry A. Soshnikov dmitry.soshnikov at gmail.com
Tue Sep 14 06:37:45 PDT 2010


  On 14.09.2010 1:03, Mark S. Miller wrote:
> On Mon, Sep 13, 2010 at 2:02 PM, Mark S. Miller <erights at google.com 
> <mailto:erights at google.com>> wrote:
>
>     On Mon, Sep 13, 2010 at 1:18 PM, Dmitry A. Soshnikov
>     <dmitry.soshnikov at gmail.com <mailto:dmitry.soshnikov at gmail.com>>
>     wrote:
>
>
>         I didn't finished a detailed reading yet, but from the brief
>         scanning, syntactically, I think /=>/ and /trait class/ are
>         not needed.
>
>
>     * I used "trait class" rather than "trait" for two reasons:
>
>         1) Syntactic ambiguity fear. "trait" is not one of the
>     identifiers reserved by ES5 or ES5/strict, and so I am not
>     proposing that it be an ES-Harmony keyword.
>

This keyword would look interesting though. Traits/mixins concept is a 
weighty thing and if to reproduce it, then in a good way -- easy to 
use/write and syntactically minimalistic. By the way, JFTR, PHP also now 
providing traits (http://wiki.php.net/rfc/horizontalreuse) with using 
this /trait TraitName {}/ syntax; Scala too has such syntax -- i.e. 
without (trait class, class trait) referencing to parser issues.


>         2) More importantly, the object binds to the name it declares
>     is not a trait but a function for making traits.
>
>
> Oops. Should be "the object bound to ..."
>
>
>     * I introduced "=>" to disambiguate whether the "{" following the
>     (trait) class head begins a block or a literal.
>

Yeah, but maybe somehow it (ambiguous) may be avoided.

>
>         /trait class EnumerableTrait() => {/
>
>         instead better:
>
>         trait Enumerable {
>
>
>     Enumerable is a function for making traits. Your syntax suggests
>     that Enumerable is itself a trait.
>

Hm, "function for making trait", "trait itself". Too many things. It may 
bring complexity. Yes, i thought (and see in other languages, the same 
Ruby) that Enumerable is a trait itself, and not a special (non-needed 
to me) function. A user needed just a trait, not a function + trait.

>
>     Without the "=>", how do we know that the "{" begins a literal
>     rather than block? (See the second TraitBody production).
>
>
>         /class Interval(min, max) => {/
>
>         instead better:
>
>         class Interval(min, max) {
>
>         or even (with initialize method)
>
>         class Interval {
>           function initialize(min, max) {}
>         }
>
>         Superfluous symbols are not needed.
>
>
>     Initialize methods are superfluous as well. Also, they introduce
>     namespace confusion and re-initialization hazards.
>

Yep, but how then you propose to initialize an instance? I mean, not a 
state, but the initial code. In the class body?

>
>         And still, don't forget about the (vertical) inheritance, i.e.
>         class Foo may /extends/ Bar. If there will be no (delegation
>         based) inheritance, such classes won't be needed, because they
>         will be just casual pattern-factories. In addition,
>         mixins/traits, being a horizontal inheritance (the
>         augmentation of the vertical code reuse) are also good to have
>         as delegation based. I think that you (and Tom) used
>         statically augmented (a method per instance) object not
>         because you like it ideologically, but because it's not
>         possible to implement it cross-browser in nowadays.
>
>
>     I'm not sure what you mean. Could you please expand and clarify
>     the question? Thanks.
>

I mentioned "classes-as-sugar" proposal, where a class cannot inherit 
(making a vertical inheritance chain).

A -> B -> C

In addition, if any class may mixin several traits/mixins, we have a 
horizontal inheritance:

A -> B -> C
|      |
|      |----------- m1 -> m3
|
|--m1 -> m2

i.e. at every link, first the whole chain of mixins is considered and 
only after that we go to the next (vertical) link. Sure, the normalized 
inheritance chain for resolution is linear:

A -> m1 -> m2 -> B -> m1 -> m3 -> C

I.e. an instance always inherits methods/properties from mixins or 
classes, but not has own (as in your implementation of classes and 
traits). The thing is not only in optimizing VM, but in dynamics of a 
language. I.e. if we modify somehow methods in the class or trait, all 
instances via delegation will have a new version.

That what Ruby uses:

module MyTrait
   def my_method
     print(@items)
   end
end

class MyCollection

   # mixin MyTrait to the class
   include MyTrait

   # and also some built-in mixin
   include Enumerable

   def initialize(data)
     @data = data
   end

   # method required by the
   # Enumerable trait/mixin
   def each
     @data.each { |i| yield(i) }
   end

end

# an intance
things = MyCollection.new(['x','yz','defgh','ij','klmno'])

thigns.my_method # from MyTrait

# available from Enumerable trait
print(things.min) #=> "defgh"
print(things.max) #=> "yz"

# aka Array#map in JS
print(things.collect { |i| i.upcase }) #=> ["X", "YZ", "DEFGH", "IJ", 
"KLMNO"]

# modules/traits are open
module Enumerable
   def new_method
     print(@items, " from new method")
   end
end

# a new method is available
# for the instance via delegation
things.new_method #=> ['x','yz','defgh','ij','klmno'] from new method

P.S.: Why am I asking? -- just see that you everywhere use static/const 
and frozen things. Want to know, do you propose JS to be a static 
language without opened classes/protos/traits/etc, "monkey-patching", etc.?

Dmitry.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20100914/c3cc9798/attachment.html>


More information about the es-discuss mailing list