On 14.09.2010 1:03, Mark S. Miller wrote:
On Mon, Sep 13, 2010 at 2:02 PM, Mark S. Miller <[email protected] <mailto:[email protected]>> wrote:

    On Mon, Sep 13, 2010 at 1:18 PM, Dmitry A. Soshnikov
    <[email protected] <mailto:[email protected]>>
    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.
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to