The parser methods are now split into their own functions. This has a number
of benefits: The most immediate is the commit that will follow. The second
benefit is that the function is no longer a closure---all context
information is passed into it, and so it can be optimized by the JavaScript
engine accordingly.
As expected, mixin method invocation is dramatically slower than
conventional class method definitions. However, it is a bit slower than I
had anticipated; future releases will definately need to take a look at
improving performance, which should happen anyway, since the trait
implementation takes the easy way out in a number of instances.
Let's get an initial release first.
Does not yet include many more detailed tests, such as method invocation
times, which will be of particular interest. While definitions are indeed
interesting, they often occur when a program is loading---when the user is
expecting to wait. Not so for method invocations.
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 is a consequence of ease.js' careful trait implementation that ensures
that any mixed in trait retains its API in the same manner that interfaces
and supertypes do.
There does not seem to be tests for any of the metadata at present; they are
implicitly tested through various implementations that make use of them.
This will also be the case here ("will"---in coming commits), but needs to
change.
The upcoming reflection implementation would be an excellent time to do so.
This will allow for additional processing before actually triggering the
warnings. For the sake of this commit, though, we just keep with existing
functionality.
This adds the `weak' keyword and permits abstract method definitions to
appear in the same definition object as the concrete implementation. This
should never be used with hand-written code---it is intended for code
generators (e.g. traits) that do not know if a concrete implementation will
be provided, and would waste cycles duplicating the property parsing that
ease.js will already be doing. It also allows for more concise code
generator code.
Note that, even though it's permitted, the validator still needs to be
modified to permit useful cases. In particular, I need weak abstract and
strong concrete methods for use in traits.
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).
More generally, this was a problem with not recursing on *all* of the
visibility objects of the supertype's supertype; the public visibility
object was implicitly recursed upon through JavaScript's natural prototype
chain, so this only manifested itself with protected members.