1
0
Fork 0
Commit Graph

5 Commits (ae196d5de535f9d028654367ef953a1318e42659)

Author SHA1 Message Date
Mike Gerwitz 90fd1a8d08
`override' implies `virtual'
This behavior is consistent with other OO languages like C++ and C# that do
not have virtual methods by default.

This solution isn't ideal, but I don't have time for a larger refactoring
right now.  I sat on this change for a good few weeks before committing it
unchanged.

* lib/MemberBuilderValidator.js (validateMethod): Allow override of
  supertype overrides.

* test/*: Stripped `virtual' keyword where appropriate.

* doc/classes.texi (Inheritance): Update to state that `override' implies
  `virtual'.
2017-06-30 02:01:40 -04:00
Mike Gerwitz b841b9cc5e
Fix trait extending of supertype with constructor
Supertypes that extend constructors may now be extended by traits without
completely blowing up.  Good feature.

* lib/Trait.js (__tconstruct): Add function.
  (createVirtProxy): Use it.

* test/Trait/ClassExtendTest.js: Add test.
2017-01-02 23:34:29 -05:00
Mike Gerwitz 903a1a135c
Prevent mixin failure on null/undefined supertype properties 2015-10-26 22:17:28 -04:00
Mike Gerwitz d9b86c1544
Support for trait class supertype overrides
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.
2015-10-24 23:53:23 -04:00
Mike Gerwitz 867127ed2f Trait class extension support
"Extending" a class C simply creates a contract stating that the trait may
only be mixed into something of type C (so, C or its subtypes).
2015-05-27 23:23:47 -04:00