From e934338b41518ecb5cb898cec25e0be44b739bdb Mon Sep 17 00:00:00 2001 From: Mike Gerwitz Date: Sun, 27 Jul 2014 01:40:35 -0400 Subject: [PATCH] Subtype ctor guarantees with parent __mixin or __construct A solution for this problem took a disproportionally large amount of time, attempting many different approaches, and arriving still at a kluge; this is indicative of a larger issue---we've long since breached the comfort of the original design, and drastic refactoring is needed. I have ideas for this, and have already started in another branch, but I cannot but this implementation off any longer while waiting for it. Sorry for anyone waiting on the next release: this is what held it up, in combination with my attention being directed elsewhere during that time (see the sparse commit timestamps). Including this ordering guarantee is very important for a stable, well-designed [trait] system. --- lib/ClassBuilder.js | 14 +++++++++++++- test/Trait/ParameterTest.js | 29 +++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/lib/ClassBuilder.js b/lib/ClassBuilder.js index dedf9bb..06bac0b 100644 --- a/lib/ClassBuilder.js +++ b/lib/ClassBuilder.js @@ -880,11 +880,17 @@ exports.prototype.createConcreteCtor = function( cname, members ) // generate and store unique instance id attachInstanceId( this, ++_self._instanceId ); - if ( typeof this.___$$ctor$pre$$ === 'function' ) + // FIXME: this is a bit of a kluge for determining whether the ctor + // should be invoked before a child prector... + var haspre = ( typeof this.___$$ctor$pre$$ === 'function' ); + if ( haspre + && ClassInstance.prototype.hasOwnProperty( '___$$ctor$pre$$' ) + ) { // FIXME: we're exposing _priv to something that can be // malicously set by the user this.___$$ctor$pre$$( _priv ); + haspre = false; } // call the constructor, if one was provided @@ -896,6 +902,12 @@ exports.prototype.createConcreteCtor = function( cname, members ) this.__construct.apply( this, ( args || arguments ) ); } + // FIXME: see above + if ( haspre ) + { + this.___$$ctor$pre$$( _priv ); + } + if ( typeof this.___$$ctor$post$$ === 'function' ) { this.___$$ctor$post$$( _priv ); diff --git a/test/Trait/ParameterTest.js b/test/Trait/ParameterTest.js index 3fb7e62..077131a 100644 --- a/test/Trait/ParameterTest.js +++ b/test/Trait/ParameterTest.js @@ -366,5 +366,34 @@ require( 'common' ).testCase( C(); } ); }, + + + /** + * The same concept as above, extended to subtypes. In particular, we + * need to ensure that the subtype is able to properly initialize or + * alter state that __mixin of a supertype depends upon. + */ + 'Subtype invokes ctor before supertype __construct or __mixin': + function() + { + var cok = false; + + var T = this.createParamTrait( function() + { + if ( !cok ) throw Error( + "__mixin called before Sub#__construct" + ); + } ); + + var Sub = this.Class( {} ).use( T ).extend( + { + __construct: function() { cok = true } + } ); + + this.assertDoesNotThrow( function() + { + Sub(); + } ); + }, } );