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