Before this change, mixin attempts would fail at the time of mixin when
easejs attempts to invoke the `__mixin` method on the object. This is both
cryptic and void of any useful information on the stack.
Traits can now override methods of their class supertypes. Previously, in
order to override a method of some class `C` by mixing in some trait `T`,
both had to implement a common interface. This had two notable downsides:
1. A trait that was only compatible with details of `C` could only work
with `C#M` if it implemented an interface `I` that declared `I#M`.
This required the author of `C` to create interfaces where they would
otherwise not be necessary.
2. As a corollary of #1---since methods of interfaces must be public, it
was not possible for `T` to override any protected method of `C`; this
meant that `C` would have to declare such methods public, which may
break encapsulation or expose unnecessary concerns to the outside
world.
Until documentation is available---hopefully in the near future---the test
cases provide detailed documentation of the behavior. Stackable traits work
as you would expect:
```javascript
var C = Class(
{
'virtual foo': function()
{
return 'C';
},
} );
var T1 = Trait.extend( C,
{
'virtual abstract override foo': function()
{
return 'T1' + this.__super();
},
} );
var T2 = Trait.extend( C,
{
'virtual abstract override foo': function()
{
return 'T2' + this.__super();
},
} );
C.use( T1 )
.use( T1 )
.use( T2 )
.use( T2 )
.foo();
// result: "T2T2T1T1C"
```
If the `override` keyword is used without `abstract`, then the super method
is statically bound to the supertype, rather than being resolved at runtime:
```javascript
var C = Class(
{
'virtual foo': function()
{
return 'C';
},
} );
var T1 = Trait.extend( C,
{
'virtual abstract override foo': function()
{
return 'T1' + this.__super();
},
} );
var T2 = Trait.extend( C,
{
// static override
'virtual override foo': function()
{
return 'T2' + this.__super();
},
} );
C.use( T1 )
.use( T1 )
.use( T2 )
.use( T2 )
.foo();
// result: "T2C"
```
This latter form should be discouraged in most circumstances (as it prevents
stackable traits), but the behavior is consistent with the rest of the
system.
Happy hacking.
I upgraded Texinfo recently and found that ease.js' documentation would no
longer compile. The errors make sense, but it's an unfortunate regression.
The previous version that I was using was 4.13, which is quite old.
This allows ease.js classes to mimic the structure of ES6 classes, which use
`constructor` to denote the constructor. This patch simply aliases it to
`__construct`, which ease.js handles as it would normally.
To that note, since the ES6 `class` keyword is purely syntatic sugar around
the prototype model, there is not much benefit to using it over ease.js if
benefits of ease.js are still desired, since the member definition syntax is
a feature of object literals:
```
// ease.js using ES6
let Person = Class(
{
_name: '',
// note that __construct still works as well
constructor( name ) {
this._name = ''+name;
},
sayHi() {
return "Hi, I'm " + this.getName();
},
// keywords still work as expected
'protected getName'() {
return this._name;
}
} );
// ES6 using `class` keyword
class Person
{
// note that ES6 will _not_ make this private
_name: '',
constructor( name ) {
this._name = ''+name;
},
sayHi() {
return "Hi, I'm " + this.getName();
}
// keywords unsupported (you'd have to use Symbols)
getName() {
return this._name;
}
}
// ES3/5 ease.js
var Person = Class(
{
_name: '',
__construct: function( name ) {
this._name = ''+name;
},
sayHi: function() {
return "Hi, I'm " + this._name;
},
'protected getName': function() {
return this._name;
}
} );
```
As you can see, the only change between writing ES6-style method definitions
is the syntax; all keywords and other features continue to work as expected.
This redefines the index as a function (rather than a vanilla object) so
that it may be invoked to yield an ease.js Class that wraps the given
prototype.
Importantly, this also removes loading from ajax.googleapis.com, which is a
problem, because the domain must be allowed using NoScript, and hosts many
other things.
Why this was added to begin with is beyond me. Perhaps it demonstrates my
novice abilities back in the day.
The previous implementation could not survive recursive applications, which
I did know about. But that was before the system was brutally abused by
traits.
Was not able to rebase because I already stupidly pushed, and Savannah does
not allow --force, or deleting `master' to circumvent. ;) Not that it would
be a good idea rergardless.
Was the key "tags" in the past? Regardless, it doesn't work [anymore], so
ease.js keywords haven't been searchable in npm for quite some time /
forever.
Even if you don't use Emacs, the outline style should be intuitive.
This commit is partially for organization, partially to let people
know that this project is still on my mind and will be getting more
attention soon.
GNU ease.js remains committed to supporting environments as far back as ES3;
unfortunately, this is important due to the popularity of older IE versions
(IE<=8). Btw, ease.js runs on IE 5.5, in case you still need that. ;)
But please don't use a proprietary web browser. Indeed, this is why the
breaks were introduced in the first place: I neglected to run the
browser-based test suite on the proprietary Microsloth browsers until after
the v0.2.3 release, because I do not own a copy of Windows; I had to run it
at work. But, regardless---my apologies; I'll be more diligent.
This is a bugfix; the bug was introduced in v0.2.3.
Notably, this caused problems in IE<=8 for non-argument traits. The problem
is that `fund.apply( x, undefined )` is not valid in ES3---we must apply an
empty array (or argument list) instead.
This is a bugfix; the bug was introduced in v0.2.3.
Initially, the implementation created a new object with the root object as
its prototype, taking advantage of ECMAScript's native
overrides/fallthroughs. Unfortunately, IE<=8 had a buggy implementation,
effectively treating the prototype as an empty object. So, rather than
alt.Array === root.Array, alt.Array === undefined.
The fix is simply to reference discrete objects.
This is a bugfix; the bug was introduced in v0.2.3.
In ECMAScript 5, reserved keywords can be used to reference the field of an
object in dot notation (e.g. method.super), but in ES3 this is prohibited;
in these cases, method['super'] must be used. To maintain ES3 compatiblity,
GNU ease.js will use the latter within its code.
Of course, if you are developing software that need not support ES3, then
you can use the dot notation yourself in your own code.
This does not sway my decision to use `super`---ES3 will soon (hopefully)
become extinct, and would be already were it not for the terrible influence
of Microsloth's outdated browsers.
Specifically, aae51ecf, which introduces deepEqual changes for comparing
argument objects---specifically, this change:
```c
if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs))
return false;
```
Since I was comparing an array with an arguments object, deepEqual failed.
While such an implementation may confuse users---since argument objects are
generally treated like arrays---the distinction is important and I do agree
with the change.
This is a bug fix.
If the provided object's constructor is an ease.js type, then the
conventional rules will apply (as mentioned in the test docblock and in the
manual); however, if it's just a vanilla ECMAScript object, then the interop
compatibility checks will be used instead.
The manual already states that this is the case; unfortunately, it
lies---this was apparently overlooked, and is a bug.