On Tue, Sep 14, 2010 at 6:37 AM, Dmitry A. Soshnikov < [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]>wrote: > >> On Mon, Sep 13, 2010 at 1:18 PM, Dmitry A. Soshnikov < >> [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? 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. > > > 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. > >> 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. > > >> >>> >>> 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.) > > 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. 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()); > > Dmitry. > -- Cheers, --MarkM
_______________________________________________ es-discuss mailing list [email protected] https://mail.mozilla.org/listinfo/es-discuss

