On 14.09.2010 20:19, Mark S. Miller wrote:
On Tue, Sep 14, 2010 at 6:37 AM, Dmitry A. Soshnikov <[email protected] <mailto:[email protected]>> wrote:

    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.


JFTR?

Sorry -- "just for the record", as already Dave has mentioned.

PHP and Scala can tolerate a much higher migration tax than JavaScript because of the differences in how they're deployed. I hesitate to propose any new keywords beyond those reserved by ES5/strict. All the proposals on <http://wiki.ecmascript.org/doku.php?id=harmony:proposals> and the current traits strawman are upwards compatible from ES5/strict, allowing a conforming implementation to provide them with no further opt-in than "use strict". Not all the strawman have this virtue, some with good reason. But to ease incremental prototyping and adoption, we should preserve this virtue when we can.


Yeah, yeah, I know, "backward compats". Forget that they are rule.



            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.


Somehow sure. Suggestions appreciated.




            /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.


Please check out <http://traitsjs.org/>. The notion of traits there and in this strawman is the "stateful traits" approach that Tom first explained at <http://prog.vub.ac.be/Publications/2009/vub-prog-tr-09-04.pdf>. Until I saw this paper, I had written traits off as a dead end.

It seems something interesting there, thanks, I'll take a look on the paper (as well as on all examples on the site). However, I'm aware that concept of a "trait" in contrast of a "mixin" has no state to avoid conflicts.


        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?

In the "Program" portion of the second TraitBody production. This can declare new variables that are captured by the following TraitLiteral. The lexical variables captured by each TraitLiteral is the state of that trait. The union of the states of the traits that a class composes together is the state of an instance.

With a state it's OK. But usually, an initialization process may include internal methods calling (which of course also just create a state properties, however, there is a difference -- conveniently to call three methods, which will set 10 properties, or to define these 10 properties manually in the body of a class).




            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


I'm still not sure I understand you correctly. But if I do, Override is your vertical composition and Compose is your horizontal composition. Via Object.create, one can also mix traits with vertical composition using the JavaScript prototype chain. But then unbound inherited methods become observable, leading to all the normal confusions. By using only Override for vertical composition, only bound methods are observable. (This is like the old "binding on extraction" property of old ES4 classes.)

Yes, regarding the end state of an object (via override/composition) you understand it correctly. But I meant exactly delegation based inheritance and asked -- why do you have (propose) a scheme where an object will have /own/ properties but not inherited? In Ruby as I showed, if we change Enumerable module (read Enumerable trait/mixin) by adding a new method "new_method" then the instance "things" of the class "MyCollection" automatically via delegation has access to the new method.

And regarding classes, I think it's not acceptable not to have inheritance and to create also own properties. Even if will be a good VM optimization, the dynamics of the languages is lost -- if we add a new method to a class -- will all instances see this new method? That exactly I'm asking.



    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.?


Not at all. As previously discussed, JavaScript will lose none of its support for monkey patching, low integrity patterns, unfrozen objects, etc. None of these proposals take any of those away.

Just to clarify and not to confuse terminology/meanings, do I understand correctly: "low integrity " -- non-|this|-bounded inherited functions, and "high integrity" -- vice-versa -- statically bound |this| and own properties? Thanks.

Further, trait classes can be instantiated with Object.create, so traits even enhance the expressiveness of low integrity patterns and vertical composition using prototypes if that's what you wish. Adapting a previous example:

    function Point(x, y) {
      this.x = x;
      this.y = y;
    }
    Point.prototype = Object.create(
      SuperPoint.prototype,
      StatelessPointTrait());


Yeah, I see. But again, instantiation of a trait creates own properties of an instance, but not just adds additional link for delegation.

By the way, the phrase "a trait instantiate" in general case contradicts to traits concept. Because in many (all?) implementations and some general definitions of traits -- traits in contrast with classes cannot instantiate objects. They are just additional modules (to add small traits for the instance).


    Dmitry.




--
    Cheers,
    --MarkM

_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to