`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'.master
parent
311118de81
commit
90fd1a8d08
|
@ -749,12 +749,10 @@ One of the following conditions must always be true:
|
||||||
@var{dfn\_n\^C} is declared with the @ref{Member Keywords,,@code{virtual}}
|
@var{dfn\_n\^C} is declared with the @ref{Member Keywords,,@code{virtual}}
|
||||||
keyword and @var{dfn\_n\^C'} is declared with the
|
keyword and @var{dfn\_n\^C'} is declared with the
|
||||||
@ref{Member Keywords,,@code{override}} keyword.
|
@ref{Member Keywords,,@code{override}} keyword.
|
||||||
@itemize
|
|
||||||
@item
|
@item
|
||||||
Note that @var{dfn\_n\^C'} will not become @ref{Member Keywords,,@code{virtual}}
|
@var{dfn\_n\^C} is declared with the @ref{Member Keywords,,@code{override}}
|
||||||
by default (unlike languages such as C++); they must be explicitly
|
keyword and @var{dfn\_n\^C'} is also declared with the
|
||||||
declared as such.
|
@ref{Member Keywords,,@code{override}} keyword.
|
||||||
@end itemize
|
|
||||||
@item
|
@item
|
||||||
@var{dfn\_n\^C} is declared with the @ref{Member Keywords,,@code{abstract}}
|
@var{dfn\_n\^C} is declared with the @ref{Member Keywords,,@code{abstract}}
|
||||||
keyword and @var{dfn\_n\^C'} omits the @ref{Member Keywords,,@code{override}}
|
keyword and @var{dfn\_n\^C'} omits the @ref{Member Keywords,,@code{override}}
|
||||||
|
@ -860,10 +858,24 @@ classes using ease.js?
|
||||||
console.log( 'Walking the dog on two feet' );
|
console.log( 'Walking the dog on two feet' );
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
// supertype override is implicitly virtual
|
||||||
|
var ReallyLazyDog = LazyDog.extend(
|
||||||
|
{
|
||||||
|
'override public walk': function()
|
||||||
|
{
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
} );
|
||||||
@end verbatim
|
@end verbatim
|
||||||
@caption{Inheritance in ease.js}
|
@caption{Inheritance in ease.js}
|
||||||
@end float
|
@end float
|
||||||
|
|
||||||
|
(The above inheritance tree is a bad idea and is for illustration
|
||||||
|
purposes only:
|
||||||
|
if you want to layer attributes,
|
||||||
|
use Traits or a composition-based pattern like Decorators.)
|
||||||
|
|
||||||
You should already understand how to define a class (@pxref{Defining
|
You should already understand how to define a class (@pxref{Defining
|
||||||
Classes}). The above example introduced two means of @dfn{extending}
|
Classes}). The above example introduced two means of @dfn{extending}
|
||||||
classes -- defining a new class that inherits from a parent:
|
classes -- defining a new class that inherits from a parent:
|
||||||
|
|
|
@ -211,7 +211,8 @@ exports.prototype.validateMethod = function(
|
||||||
}
|
}
|
||||||
|
|
||||||
// disallow overriding non-virtual methods
|
// disallow overriding non-virtual methods
|
||||||
if ( keywords[ 'override' ] && !( prev_keywords[ 'virtual' ] ) )
|
if ( keywords[ 'override' ]
|
||||||
|
&& !( prev_keywords[ 'virtual' ] || prev_keywords[ 'override' ] ) )
|
||||||
{
|
{
|
||||||
if ( !( keywords[ 'abstract' ] ) )
|
if ( !( keywords[ 'abstract' ] ) )
|
||||||
{
|
{
|
||||||
|
|
|
@ -192,9 +192,18 @@ require( 'common' ).testCase(
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overriding a method in ease.js does not immediately make it virtual.
|
* An override is implicitly virtual. This was not always the case:
|
||||||
* Rather, the virtual keyword must be explicitly specified. Let's ensure
|
* prior to v0.2.9, an override did not imply virtual.
|
||||||
* that it is permitted.
|
*/
|
||||||
|
'Can override overridden method with concrete method': function()
|
||||||
|
{
|
||||||
|
this.quickKeywordMethodTest( [ 'override' ], null, [ 'override' ] );
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For legacy reasons; see above test. In the future, this might
|
||||||
|
* trigger a notice, since it's redundant. No harm in being explicit!
|
||||||
*/
|
*/
|
||||||
'Can declare override as virtual': function()
|
'Can declare override as virtual': function()
|
||||||
{
|
{
|
||||||
|
|
|
@ -485,7 +485,7 @@ require( 'common' ).testCase(
|
||||||
|
|
||||||
var T1 = this.Sut.extend( C,
|
var T1 = this.Sut.extend( C,
|
||||||
{
|
{
|
||||||
'virtual abstract override foo': function()
|
'abstract override foo': function()
|
||||||
{
|
{
|
||||||
return 3 + this.__super();
|
return 3 + this.__super();
|
||||||
},
|
},
|
||||||
|
@ -493,7 +493,7 @@ require( 'common' ).testCase(
|
||||||
|
|
||||||
var T2 = this.Sut.extend( C,
|
var T2 = this.Sut.extend( C,
|
||||||
{
|
{
|
||||||
'virtual abstract override foo': function()
|
'abstract override foo': function()
|
||||||
{
|
{
|
||||||
return 13 + this.__super();
|
return 13 + this.__super();
|
||||||
},
|
},
|
||||||
|
@ -533,7 +533,7 @@ require( 'common' ).testCase(
|
||||||
|
|
||||||
var T1 = this.Sut.extend( C,
|
var T1 = this.Sut.extend( C,
|
||||||
{
|
{
|
||||||
'virtual override foo': function()
|
'override foo': function()
|
||||||
{
|
{
|
||||||
return 3 + this.__super();
|
return 3 + this.__super();
|
||||||
},
|
},
|
||||||
|
@ -541,7 +541,7 @@ require( 'common' ).testCase(
|
||||||
|
|
||||||
var T2 = this.Sut.extend( C,
|
var T2 = this.Sut.extend( C,
|
||||||
{
|
{
|
||||||
'virtual override foo': function()
|
'override foo': function()
|
||||||
{
|
{
|
||||||
return 13 + this.__super();
|
return 13 + this.__super();
|
||||||
},
|
},
|
||||||
|
@ -603,7 +603,7 @@ require( 'common' ).testCase(
|
||||||
var T2 = this.Sut.extend( C,
|
var T2 = this.Sut.extend( C,
|
||||||
{
|
{
|
||||||
// T1 provides a concrete method that we can override
|
// T1 provides a concrete method that we can override
|
||||||
'virtual abstract override concrete': function()
|
'abstract override concrete': function()
|
||||||
{
|
{
|
||||||
return 5 + this.__super();
|
return 5 + this.__super();
|
||||||
},
|
},
|
||||||
|
|
|
@ -137,7 +137,7 @@ require( 'common' ).testCase(
|
||||||
|
|
||||||
var Ta = this.Sut.implement( I ).extend(
|
var Ta = this.Sut.implement( I ).extend(
|
||||||
{
|
{
|
||||||
'virtual abstract override foo': function()
|
'abstract override foo': function()
|
||||||
{
|
{
|
||||||
called.a = true;
|
called.a = true;
|
||||||
this.__super();
|
this.__super();
|
||||||
|
@ -182,7 +182,7 @@ require( 'common' ).testCase(
|
||||||
|
|
||||||
var T = this.Sut.implement( I ).extend(
|
var T = this.Sut.implement( I ).extend(
|
||||||
{
|
{
|
||||||
'virtual abstract override foo': function()
|
'abstract override foo': function()
|
||||||
{
|
{
|
||||||
called++;
|
called++;
|
||||||
this.__super();
|
this.__super();
|
||||||
|
|
|
@ -340,7 +340,7 @@ require( 'common' ).testCase(
|
||||||
this.assertStrictEqual( expected,
|
this.assertStrictEqual( expected,
|
||||||
this.Class.use( T ).extend(
|
this.Class.use( T ).extend(
|
||||||
{
|
{
|
||||||
'override virtual foo': function()
|
'override foo': function()
|
||||||
{
|
{
|
||||||
return this.__super();
|
return this.__super();
|
||||||
},
|
},
|
||||||
|
|
|
@ -55,9 +55,9 @@ var Cv = Class.implement( I ).extend(
|
||||||
|
|
||||||
var To = Trait.implement( I ).extend(
|
var To = Trait.implement( I ).extend(
|
||||||
{
|
{
|
||||||
'virtual abstract override a': function() {},
|
'abstract override a': function() {},
|
||||||
'virtual abstract override b': function() {},
|
'abstract override b': function() {},
|
||||||
'virtual abstract override c': function() {},
|
'abstract override c': function() {},
|
||||||
} );
|
} );
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue