During its initial development, no environments (e.g. Node.js, Chromium,
Firefox) supported strict mode; this has since changed, and node has a
--use-strict option, which is used in the test runner to ensure conformance.
This fixes a bug that causesd virtual definitions with parameters on classes
that a trait is mixed into to fail, and prevented proper param length
validations in the reverse case.
See test case description for a less confusing description.
This allows separation of concerns and makes the type system extensible. If
the type does not implement the necessary API, it falls back to using
instanceof.
I feel like I originally did this because older versions of node didn't like
relative paths (unless maybe the cwd wasn't in NODE_PATH). Regardless, it works
now, and this is cleaner.
Further, I noticed that __dirname didn't seem to be working properly with
browserify. While GNU ease.js does not make use of it (ease.js uses its own
scripts), other projects may.
These will be supported in future versions; this is not something that I
want to rush, nor is it something I want to hold up the first GNU release;
it is likely to be a much lesser-used feature.
The concept of stacked traits already existed in previous commits, but until
now, mixins could not be stacked without some ugly errors. This also allows
mixins to be stacked atop of themselves, duplicating their effect. This
would naturally have limited use, but it's there.
This differs slightly from Scala. For example, consider this ease.js mixin:
C.use( T ).use( T )()
This is perfectly valid---it has the effect of stacking T twice. In reality,
ease.js is doing this:
- C' = C.use( T );
- new C'.use( T );
That is, it each call to `use' creates another class with T mixed in.
Scala, on the other hand, complains in this situation:
new C with T with T
will produce an error stating that "trait T is inherited twice". You can
work around this, however, by doing this:
class Ca extends T
new Ca with T
In fact, this is precisely what ease.js is doing, as mentioned above; the
"use.use" syntax is merely shorthand for this:
new C.use( T ).extend( {} ).use( T )
Just keep that in mind.
More information on this implementation and the rationale behind it will
appear in the manual. See future commits.
(Note the TODOs; return values aren't quite right here, but that will be
handled in the next commit.)
This just saves some time and memory in the event that the trait is never
actually used, which may be the case in libraries or dynamically loaded
modules.
As described in <https://savannah.gnu.org/task/index.php#comment3>.
The benefit of this approach over definition object merging is primarily
simplicitly---we're re-using much of the existing system. We may provide
more tight integration eventually for performance reasons (this is a
proof-of-concept), but this is an interesting start.
This also allows us to study and reason about traits by building off of
existing knowledge of composition; the documentation will make mention of
this to explain design considerations and issues of tight coupling
introduced by mixing in of traits.
Note the incomplete tests. These are very important, but the current state
at least demonstrates conceptually how this will work (and is even useful in
its current state, albeit dangerous and far from ready for production).
This is a rough concept showing how traits will be used at definition time
by classes (note that this does not yet address how they will be ``mixed
in'' at the time of instantiation).