From: [email protected] [mailto:[email protected]] On 
Behalf Of Dmitry A. Soshnikov
Sent: Sunday, October 10, 2010 3:58 AM
To: Tom Van Cutsem
Cc: Mark S. Miller; [email protected]
Subject: Re: "Syntax for Efficient Traits" is now ready for discussion

On 07.10.2010 22:21, Tom Van Cutsem wrote:
Hi Dmitry,

Hi MarkM and Tom, possibly it will be interesting to you: 
http://gist.github.com/613924 -- a delegation based mixins implemented using 
Harmony proxies.

Features:

  - working in two modes: traits (naming conflict predicting at early stage), 
or simple linearization (mixins mode, there is no warning about naming 
conflicts);

  - "in" operator is working on object (e.g. "foo" in bar is true if either bar 
has own property "foo", or any of mixed objects have the property (including 
consideration of their prototype and mixin chains), or if the property is found 
in the prototype chain of the bar).

Cons: possible overhead on reading / or testing for "in". Should be avoided at 
lower level implementation.

TODO: syntactic sugar (possibly for CoffeeScript).

It's an interesting experiment. On first sight, your inheritance mechanism 
looks very similar to Ruby's modules.

Yes, Ruby also uses hidden proxy-class to communicate with a mixin module.


Although one big difference is that in your experiment, your mixins can also 
have their own prototype chain (IIRC in Ruby, modules can't inherit).

Yeah, not for user-defined inheritance. But modules there inherit though form 
some general built-in classes (i.e. Object, BasicObject, Class, etc).

For Ruby, BasicObject is the base type, Object inherits from it, and everything 
else inherits from Object. Object also mixes in Kernel.

Module derives directly from Object, but that's because Module is a class. 
(oddly enough, Module.superclass == Object, Module.class == Class, and 
Class.superclass = Module).

Modules themselves do not inherit from anything, because they are instances of 
the Module class (this is why Kernel.ancestors == [Kernel]). Note that modules 
do have singleton_classes.

I think that may be a bit too flexible, leading to even more complex lookups 
than is the case with multiple inheritance. If you would ignore the prototype 
of the mixins, you end up with something called "comb inheritance" (at each 
level, check the object and the mixins horizontally, if not found go up one 
level on the prototype chain and try again) which is a bit more tractable for 
programmers to deal with, I think.


Yes, such implementation is also possible. Moreover, implementation is very 
easy -- Module.new will be just Object.create(null). On the other hand, it's 
not required to be a complete clone of Ruby's modules. It may be better, though 
;) But it prototypes of modules bring inconvenience and confusion, I'll make 
them prototype-less.


Your experiment does show that it's possible to combine conflict detection + 
delegation to some extend. However, I wouldn't call your conflict detection 
mode "trait mode".

Of course, because it's a similar to Ruby's module system though -- with 
liniarization, but not traits in respect of conflict predicting; I added 
"traitsMode" just to enable this small ability to warning an issue. And again, 
backing to classical traits, e.g. Ruby's Enumerable module -- is a trait: (1) 
it doesn't not have a state, (2) it does not break the state of classes/objects 
to which it mixied/include and (3) it does brings additional functionality 
based on the sate of an object (possibly, state provided by the class 
definition -- including needed methods and properties). And that this system 
does not provide naming conflict detection -- well, it's just one of possible 
implementations. It choosen linearzation though, to keep dynamics and reusing. 
I combined it providing a very basic of naming conflict detection.


First: the system is not conflict-proof: if some code adds a property to a 
mixin object or to the target object at a later point in time, potential 
conflicts will go undetected.

Theoretically it's possible to implement (e.g. store for a module list of 
objects/classes to which it included, and trap all [[Set]] generic set with 
checking, whether the new name is in some object. The same for objects). But 
practically it will be unnecessary overhead.


Second, even in "trait mode" the ordering of the mixins matters (trait 
composition is commutative, ordering is not important, at any level of 
composition).

Of course, if a composed (from several static modules/traits/mixins) "holy" 
object has all of those properties/methods as own, the order is not essential. 
But if to consider exactly reusing of the code, with inheritance, the order 
does matter. Also, since you freeze your traits, it moves to statics anyway 
(hello, Java) and you can't extend a trait anyway -- yeah, no extension, no 
problem with later naming conflict detection.


Third, there seems to be no obvious way to resolve/avoid a signaled conflict 
(traits have aliasing or overriding to deal with this).

Personally, I think that as long as it is well-defined (i.e. last defined 
method "wins") it will be fine.


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

Reply via email to