phetsims / tandem

Simulation-side code for PhET-iO
MIT License
0 stars 5 forks source link

Eliminate the need for PhET-iO wrapper instances #210

Closed samreid closed 4 years ago

samreid commented 4 years ago

From https://github.com/phetsims/tandem/issues/188#issuecomment-689779651

PhetioObject calls:

this.phetioWrapper = new this.phetioType( this, this.tandem.phetioID );

However, it is unimportant that the IO Type constructor be used to create the wrapper. The wrapper just consists of a phetioID and phetioObject. We should eliminate this unnecessary use of ObjectIO's constructor.

samreid commented 4 years ago

phetioCommandProcessor invokes the method like so:

const result = methodSignature.implementation.apply( wrapper, args );

I asked @zepumph which is better between:

    setValue: {
      returnType: VoidIO,
      parameterTypes: [ parameterType ],
      implementation: function( value ) {
        this.set( value );
      },
      documentation: 'Sets the value of the Property. If the value differs from the previous value, listeners are ' +
                     'notified with the new value.',
      invocableForReadOnlyElements: false
    },

and

    setValue: {
      returnType: VoidIO,
      parameterTypes: [ parameterType ],
      implementation: function( property,value ) {
        property.set( value );
      },
      documentation: 'Sets the value of the Property. If the value differs from the previous value, listeners are ' +
                     'notified with the new value.',
      invocableForReadOnlyElements: false
    },

And he recommended using this.

I mentioned we could create a backward compatible patch like so:

const result = methodSignature.implementation.apply( { phetioObject: targetObject }, args );

But using this may be clearest. I'll make that change as part of this changeset.

samreid commented 4 years ago

I have many things working nicely, and the wrapper type eliminated completely.

```diff Index: main/axon/js/ObservableArrayIO.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- main/axon/js/ObservableArrayIO.js (revision fc83bd549a1b358061c8393b0409d8c7bde48bf8) +++ main/axon/js/ObservableArrayIO.js (date 1599704243595) @@ -96,7 +96,7 @@ returnType: VoidIO, parameterTypes: [ FunctionIO( VoidIO, [ parameterType ] ) ], implementation: function( listener ) { - this.phetioObject.addItemAddedListener( listener ); + this.addItemAddedListener( listener ); }, documentation: 'Add a listener that is called when an item is added to the observable array.' }, @@ -110,7 +110,7 @@ returnType: VoidIO, parameterTypes: [ FunctionIO( VoidIO, [ parameterType ] ) ], implementation: function( listener ) { - this.phetioObject.addItemRemovedListener( listener ); + this.addItemRemovedListener( listener ); }, documentation: 'Add a listener that is called when an item is removed from the observable array.' }, @@ -122,7 +122,7 @@ returnType: NumberIO, parameterTypes: [], implementation: function() { - return this.phetioObject.length; + return this.length; }, documentation: 'Get the number of elements in the observable array' } Index: main/scenery/js/nodes/IndexedNodeIO.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- main/scenery/js/nodes/IndexedNodeIO.js (revision c6b0dc1e26c0cd533f027ea725723c8b19709c60) +++ main/scenery/js/nodes/IndexedNodeIO.js (date 1599704243638) @@ -36,7 +36,7 @@ returnType: VoidIO, parameterTypes: [], implementation: function() { - return this.phetioObject.moveForward(); + return this.moveForward(); }, documentation: 'Move this node one index forward in each of its parents. If the node is already at the front, this is a no-op.' }, @@ -45,7 +45,7 @@ returnType: VoidIO, parameterTypes: [], implementation: function() { - return this.phetioObject.moveBackward(); + return this.moveBackward(); }, documentation: 'Move this node one index backward in each of its parents. If the node is already at the back, this is a no-op.' } Index: main/charges-and-fields/js/charges-and-fields/model/ChargedParticle.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- main/charges-and-fields/js/charges-and-fields/model/ChargedParticle.js (revision 56a9c2215d7ed272069b44f605d8293e98105257) +++ main/charges-and-fields/js/charges-and-fields/model/ChargedParticle.js (date 1599704243621) @@ -75,7 +75,7 @@ returnType: VoidIO, parameterTypes: [ NumberIO ], implementation: function( value ) { - this.phetioObject.charge = value.charge; + this.charge = value.charge; }, documentation: 'Set charge (in units of e)', invocableForReadOnlyElements: false Index: main/axon/js/Emitter.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- main/axon/js/Emitter.js (revision fc83bd549a1b358061c8393b0409d8c7bde48bf8) +++ main/axon/js/Emitter.js (date 1599704243626) @@ -162,7 +162,7 @@ returnType: VoidIO, parameterTypes: [ FunctionIO( VoidIO, parameterTypes ) ], implementation: function( listener ) { - this.phetioObject.addListener( listener ); + this.addListener( listener ); }, documentation: 'Adds a listener which will be called when the emitter emits.' }, @@ -172,7 +172,7 @@ // Match `Emitter.emit`'s dynamic number of arguments implementation: function() { - this.phetioObject.emit.apply( this.phetioObject, arguments ); + this.emit.apply( this.phetioObject, arguments ); }, documentation: 'Emits a single event to all listeners.', invocableForReadOnlyElements: false Index: main/phet-io/js/PhetioEngineIO.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- main/phet-io/js/PhetioEngineIO.js (revision 371809713cf6b35ee3bb10c36663d95c8c19f1a0) +++ main/phet-io/js/PhetioEngineIO.js (date 1599697790220) @@ -21,12 +21,12 @@ import phetio from './phetio.js'; class PhetioEngineIO extends ObjectIO { - constructor( phetioEngine, phetioID ) { - super( phetioEngine, phetioID ); - - // @private - to simplify readability in the methods below - this.phetioEngine = this.phetioObject; - } + // constructor( phetioEngine, phetioID ) { + // super( phetioEngine, phetioID ); + // + // // @private - to simplify readability in the methods below + // this.phetioEngine = this.phetioObject; + // } } PhetioEngineIO.methods = { @@ -40,7 +40,7 @@ const values = {}; for ( let i = 0; i < phetioIDs.length; i++ ) { const phetioID = phetioIDs[ i ]; - const wrapper = this.phetioEngine.getWrapper( phetioID ); + const wrapper = this.phetioEngine.getPhetioObject( phetioID ); values[ phetioID ] = wrapper.getValue(); } return values; @@ -55,7 +55,7 @@ // 3rd is {Object} from PhetioStateEngine.getStateForObject() or {} if phetioState: false parameterTypes: [ FunctionIO( VoidIO, [ StringIO, ObjectIO, ObjectIO ] ) ], implementation: function( listener ) { - this.phetioEngine.addPhetioObjectAddedListener( listener ); + this.addPhetioObjectAddedListener( listener ); }, documentation: 'Adds a listener that receives a callback when a PhET-iO Element has been added.' + 'Arguments for the function: \n
    ' + @@ -69,7 +69,7 @@ returnType: VoidIO, parameterTypes: [ FunctionIO( VoidIO, [ ObjectIO ] ) ], implementation: function( listener ) { - this.phetioEngine.phetioTypesAddedEmitter.addListener( listener ); + this.phetioTypesAddedEmitter.addListener( listener ); }, documentation: 'Adds a listener that receives a callback when an IO Type has been added' + 'Arguments for the function: \n
      ' + @@ -81,7 +81,7 @@ returnType: VoidIO, parameterTypes: [ FunctionIO( VoidIO, [ StringIO, StringIO ] ) ], implementation: function( listener ) { - this.phetioEngine.addPhetioObjectRemovedListener( listener ); + this.addPhetioObjectRemovedListener( listener ); }, documentation: 'Removes a listener that was added with addPhetioElementAddedListener' }, @@ -114,7 +114,7 @@ returnType: VoidIO, parameterTypes: [ FunctionIO( VoidIO, [ ObjectIO ] ) ], implementation: function( listener ) { - this.phetioEngine.addPhetioElementsBaselineListener( listener ); + this.addPhetioElementsBaselineListener( listener ); }, documentation: 'Adds a listener that receives a message when the simulation baseline file is prepared. For internal usage only.' }, @@ -181,7 +181,7 @@ returnType: ArrayIO( StringIO ), parameterTypes: [], implementation: function() { - return this.phetioEngine.getPhetioIDs(); + return this.getPhetioIDs(); }, documentation: 'Gets a list of all of the PhET-iO elements.' }, @@ -190,7 +190,7 @@ returnType: ArrayIO( StringIO ), parameterTypes: [], implementation: function() { - return this.phetioEngine.getFeaturedPhetioIDs(); + return this.getFeaturedPhetioIDs(); }, documentation: 'Gets a list of the featured PhET-iO elements.' }, @@ -199,7 +199,7 @@ returnType: ObjectIO, parameterTypes: [], implementation: function() { - return this.phetioEngine.phetioStateEngine.getState(); + return this.phetioStateEngine.getState(); }, documentation: 'Gets the full state of the simulation, including parts that have not changed from startup.' }, @@ -208,7 +208,7 @@ returnType: ObjectIO, parameterTypes: [], implementation: function() { - return this.phetioEngine.phetioStateEngine.getChangedState(); + return this.phetioStateEngine.getChangedState(); }, documentation: 'Gets the state of the simulation, only returning values that have changed from their initial state. ' + 'PhET-iO elements that have been deleted will be displayed with the value "DELETED".' @@ -218,7 +218,7 @@ returnType: ObjectIO, parameterTypes: [ StringIO ], implementation: function( phetioID ) { - return this.phetioEngine.phetioStateEngine.getStateForObject( phetioID ); + return this.phetioStateEngine.getStateForObject( phetioID ); }, documentation: 'Gets the state object for a PhET-iO element or null if phetioID does not exist.' }, @@ -227,7 +227,7 @@ returnType: VoidIO, parameterTypes: [ ObjectIO ], implementation: function( state ) { - this.phetioEngine.phetioStateEngine.setFullState( state ); + this.phetioStateEngine.setFullState( state ); }, documentation: 'Sets the simulation state based on the keys provided. The parameter is a map where the keys are ' + 'phetioIDs and the values are the corresponding states for each PhET-iO element. This method expects' + @@ -243,7 +243,7 @@ implementation: function( phetioID ) { // this is the same implementation as the third argument in the addPhetioElementAddedListener function, these should stay in sync. - return this.phetioEngine.getPhetioObject( phetioID ).getMetadata(); + return this.getPhetioObject( phetioID ).getMetadata(); }, documentation: 'Get metadata about the PhET-iO element. This includes the following keys:
        ' + '
      • phetioTypeName: The name of the PhET-iO Type\n
      • ' + @@ -334,7 +334,7 @@ returnType: VoidIO, parameterTypes: [ NumberIO, NumberIO ], implementation: function( width, height ) { - this.phetioEngine.setDisplaySize( width, height ); + this.setDisplaySize( width, height ); }, documentation: 'Sets the size of the visible region for the simulation. In most cases, it would be recommended to ' + 'set the size of the iframe, but this method can be used to set the size of the display inside the ' + Index: main/phet-io/js/phetioCommandProcessor.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- main/phet-io/js/phetioCommandProcessor.js (revision 371809713cf6b35ee3bb10c36663d95c8c19f1a0) +++ main/phet-io/js/phetioCommandProcessor.js (date 1599701649428) @@ -224,11 +224,13 @@ phet.phetio.phetioEngine.errorIfUndefined( phetioID ); // Load phetio from the namespace to avoid a module cycle - let wrapper = phet.phetio.phetioEngine.getWrapper( phetioID ); + let targetPhetioID = phetioID; + let targetObject = phet.phetio.phetioEngine.getPhetioObject( phetioID ); // If we are a LinkedElementIO, then forward the call onto the element that is being linked to. - if ( wrapper.phetioObject.phetioType === LinkedElementIO ) { - wrapper = phet.phetio.phetioEngine.getWrapper( wrapper.phetioObject.element.tandem.phetioID ); + if ( targetObject.phetioType === LinkedElementIO ) { + targetPhetioID = targetObject.element.tandem.phetioID; + targetObject = phet.phetio.phetioEngine.getPhetioObject( targetPhetioID ); } // Search up the chain to get the specified method. @@ -247,19 +249,19 @@ }; // {Object} - the method definition for an IO Type, see PropertyIO for examples - const methodSignature = getMethodSignature( wrapper.constructor, method ); + const methodSignature = getMethodSignature( targetObject.phetioType, method ); if ( !methodSignature ) { throw new Error( 'method not found: ' + phetioID + '.' + method ); } // Check for exact value of false instead of just truthiness because invocableForReadOnlyElements is often undefined - if ( wrapper.phetioObject.phetioReadOnly && methodSignature.invocableForReadOnlyElements === false ) { + if ( targetObject.phetioReadOnly && methodSignature.invocableForReadOnlyElements === false ) { throw new Error( 'Cannot invoke method \'' + method + '\' on read-only element \'' + phetioID + '\'' ); } // archetypes can't have methods called on them, see https://github.com/phetsims/phet-io-wrappers/issues/302 - if ( wrapper.phetioObject.phetioIsArchetype ) { + if ( targetObject.phetioIsArchetype ) { throw new Error( 'Cannot invoke method \'' + method + '\' on dynamic element archetype \'' + phetioID + '\'' ); } @@ -283,7 +285,7 @@ // Invoke the method. If it throws an error, it will be caught in handleSingleInvoke and returned to the client // See https://github.com/phetsims/phet-io/issues/941 - const result = methodSignature.implementation.apply( wrapper, args ); + const result = methodSignature.implementation.apply( targetObject, args ); // Serialize the result if possible. return methodSignature.returnType.toStateObject( result ); Index: main/bending-light/js/common/model/MediumIO.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- main/bending-light/js/common/model/MediumIO.js (revision ca0d2e303b05e5f37971f8b8ece81ea8a92f5fcc) +++ main/bending-light/js/common/model/MediumIO.js (date 1599704243601) @@ -47,7 +47,7 @@ returnType: VoidIO, parameterTypes: [ StringIO ], implementation: text => { - this.phetioObject.name = text; + this.name = text; }, documentation: 'Set the name of the solute', invocableForReadOnlyElements: false @@ -57,7 +57,7 @@ returnType: VoidIO, parameterTypes: [ StringIO ], implementation: text => { - this.phetioObject.formula = text; + this.formula = text; }, documentation: 'Set the formula of the solute', invocableForReadOnlyElements: false Index: main/tandem/js/PhetioObject.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- main/tandem/js/PhetioObject.js (revision 9422eb38230c82c00645ce24c98665b97831dbd0) +++ main/tandem/js/PhetioObject.js (date 1599701588401) @@ -151,11 +151,6 @@ // @public (read-only) {Object} - see docs at DEFAULTS declaration this.phetioComponentOptions = DEFAULTS.phetioComponentOptions; - // @public (read-only) {ObjectIO|null} - assigned in initializePhetioObject - the instantiated IO Type. The phetioWrapper - // is the API layer between the wrapper and the phetioObject. It's used to call methods on this phetioObject from - // the wrapper frame. Will be null if this PhetioObject is never instrumented. - this.phetioWrapper = null; - // @private {boolean} - track whether the object has been initialized. This is necessary because initialization // can happen in the constructor or in a subsequent call to initializePhetioObject (to support scenery Node) this.phetioObjectInitialized = false; @@ -336,9 +331,6 @@ if ( PHET_IO_ENABLED && this.isPhetioInstrumented() ) { assert && Tandem.VALIDATION && assert( !this.phetioType.uninstrumented, 'cannot instantiate a phetioType that should not be instrumented' ); - - // @public (read-only phet-io-internal) - this.phetioWrapper = new this.phetioType( this, this.tandem.phetioID ); } this.tandem.addPhetioObject( this ); this.phetioObjectInitialized = true; @@ -551,7 +543,6 @@ if ( this.phetioObjectInitialized ) { this.tandem.removePhetioObject( this ); - this.phetioWrapper && this.phetioWrapper.dispose && this.phetioWrapper.dispose(); } // Dispose LinkedElements Index: main/axon/js/DerivedPropertyIO.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- main/axon/js/DerivedPropertyIO.js (revision fc83bd549a1b358061c8393b0409d8c7bde48bf8) +++ main/axon/js/DerivedPropertyIO.js (date 1599704243630) @@ -74,7 +74,7 @@ returnType: VoidIO, parameterTypes: [ parameterType ], implementation: function( value ) { - return this.phetioObject.set( value ); + return this.set( value ); }, documentation: 'Errors out when you try to set a derived property.', invocableForReadOnlyElements: false Index: main/build-an-atom/js/game/model/BAAGameModelIO.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- main/build-an-atom/js/game/model/BAAGameModelIO.js (revision 0b468fe467ce99a8a8dc1cf73d3b6cddf69e0ffa) +++ main/build-an-atom/js/game/model/BAAGameModelIO.js (date 1599704243634) @@ -38,7 +38,7 @@ returnType: VoidIO, parameterTypes: [ StringIO ], implementation: function( levelType ) { - this.phetioObject.startGameLevel( levelType ); + this.startGameLevel( levelType ); }, documentation: 'Start one of the following games: periodic-table-game, mass-and-charge-game, symbol-game, advanced-symbol-game', invocableForReadOnlyElements: false @@ -51,7 +51,7 @@ returnType: VoidIO, parameterTypes: [ ArrayIO( ArrayIO( ObjectIO ) ) ], implementation: function( challenges ) { - this.phetioObject.setChallenges( challenges ); + this.setChallenges( challenges ); }, documentation: 'Specify exact challenges', invocableForReadOnlyElements: false @@ -66,7 +66,7 @@ // TODO: change this to take index as 1st argument (for level index) implementation: function( allowedChallengeTypesByLevel ) { - this.phetioObject.setAllowedChallengeTypesByLevel( allowedChallengeTypesByLevel ); + this.setAllowedChallengeTypesByLevel( allowedChallengeTypesByLevel ); }, documentation: 'Specify which challenge types may be presented to the user for each level.', Index: main/beers-law-lab/js/concentration/model/SoluteIO.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- main/beers-law-lab/js/concentration/model/SoluteIO.js (revision 58705d4f93efa1637353f937a5f8c1a50b4ed4f1) +++ main/beers-law-lab/js/concentration/model/SoluteIO.js (date 1599704243609) @@ -22,7 +22,7 @@ returnType: VoidIO, parameterTypes: [ StringIO ], implementation: text => { - this.phetioObject.name = text; + this.name = text; }, documentation: 'Set the name of the solute', invocableForReadOnlyElements: false @@ -32,7 +32,7 @@ returnType: VoidIO, parameterTypes: [ StringIO ], implementation: text => { - this.phetioObject.formula = text; + this.formula = text; }, documentation: 'Set the formula of the solute', invocableForReadOnlyElements: false Index: main/utterance-queue/js/UtteranceQueueIO.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- main/utterance-queue/js/UtteranceQueueIO.js (revision 72254e51b327eeb6e16cdb2a33a5948b203edc50) +++ main/utterance-queue/js/UtteranceQueueIO.js (date 1599704243657) @@ -19,7 +19,7 @@ returnType: VoidIO, parameterTypes: [ StringIO ], implementation: function( textContent ) { - return this.phetioObject.addToBack( textContent ); + return this.addToBack( textContent ); }, documentation: 'Add the utterance (string) to the end of the queue.', invocableForReadOnlyElements: false @@ -29,7 +29,7 @@ returnType: VoidIO, parameterTypes: [ StringIO ], implementation: function( textContent ) { - return this.phetioObject.addToFront( textContent ); + return this.addToFront( textContent ); }, documentation: 'Add the utterance (string) to the beginning of the queue.', invocableForReadOnlyElements: false @@ -39,7 +39,7 @@ returnType: VoidIO, parameterTypes: [ BooleanIO ], implementation: function( muted ) { - this.phetioObject.muted( muted ); + this.muted( muted ); }, documentation: 'Set whether the utteranceQueue will be muted or not. If muted, utterances still move through the ' + 'queue but will not be read by screen readers.', @@ -49,7 +49,7 @@ returnType: BooleanIO, parameterTypes: [ VoidIO ], implementation: function() { - return this.phetioObject.muted(); + return this.muted(); }, documentation: 'Get whether the utteranceQueue is muted. If muted, utterances still move through the ' + 'queue but will not be read by screen readers.' @@ -58,7 +58,7 @@ returnType: VoidIO, parameterTypes: [ BooleanIO ], implementation: function( enabled ) { - this.phetioObject.enabled( enabled ); + this.enabled( enabled ); }, documentation: 'Set whether the utteranceQueue will be enabled or not. When enabled, Utterances cannot be added to ' + 'the queue, and the Queue cannot be cleared. Also nothing will be sent to assistive technology.', @@ -68,7 +68,7 @@ returnType: BooleanIO, parameterTypes: [ VoidIO ], implementation: function() { - return this.phetioObject.enabled(); + return this.enabled(); }, documentation: 'Get whether the utteranceQueue is enabled. When enabled, Utterances cannot be added to ' + 'the queue, and the Queue cannot be cleared. Also nothing will be sent to assistive technology.' Index: main/scenery/js/nodes/TextIO.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- main/scenery/js/nodes/TextIO.js (revision c6b0dc1e26c0cd533f027ea725723c8b19709c60) +++ main/scenery/js/nodes/TextIO.js (date 1599704243675) @@ -59,7 +59,7 @@ returnType: VoidIO, parameterTypes: [ FontIO ], implementation: function( font ) { - this.phetioObject.setFont( font ); + this.setFont( font ); }, documentation: 'Sets font options for this TextIO instance, e.g. {size: 16, weight: bold}. If increasing the font ' + 'size does not make the text size larger, you may need to increase the maxWidth of the TextIO also.', @@ -70,7 +70,7 @@ returnType: FontIO, parameterTypes: [], implementation: function() { - return this.phetioObject.getFont(); + return this.getFont(); }, documentation: 'Gets font options for this TextIO instance as an object' }, @@ -79,7 +79,7 @@ returnType: VoidIO, parameterTypes: [ NumberIO ], implementation: function( maxWidth ) { - this.phetioObject.setMaxWidth( maxWidth ); + this.setMaxWidth( maxWidth ); }, documentation: 'Sets the maximum width of text box. ' + 'If the text width exceeds maxWidth, it is scaled down to fit.', @@ -90,7 +90,7 @@ returnType: NumberIO, parameterTypes: [], implementation: function() { - return this.phetioObject.maxWidth; + return this.maxWidth; }, documentation: 'Gets the maximum width of text box' } Index: main/axon/js/PropertyIO.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- main/axon/js/PropertyIO.js (revision fc83bd549a1b358061c8393b0409d8c7bde48bf8) +++ main/axon/js/PropertyIO.js (date 1599704243615) @@ -112,7 +112,7 @@ returnType: parameterType, parameterTypes: [], implementation: function() { - return this.phetioObject.get(); + return this.get(); }, documentation: 'Gets the current value.' }, @@ -121,7 +121,7 @@ returnType: VoidIO, parameterTypes: [ parameterType ], implementation: function( value ) { - this.phetioObject.set( value ); + this.set( value ); }, documentation: 'Sets the value of the Property. If the value differs from the previous value, listeners are ' + 'notified with the new value.', @@ -134,7 +134,7 @@ // oldValue will start as "null" the first time called parameterTypes: [ FunctionIO( VoidIO, [ parameterType, NullableIO( parameterType ) ] ) ], implementation: function( listener ) { - this.phetioObject.link( listener ); + this.link( listener ); }, documentation: 'Adds a listener which will be called when the value changes. On registration, the listener is ' + 'also called with the current value. The listener takes two arguments, the new value and the ' + @@ -147,7 +147,7 @@ // oldValue will start as "null" the first time called parameterTypes: [ FunctionIO( VoidIO, [ parameterType, NullableIO( parameterType ) ] ) ], implementation: function( listener ) { - this.phetioObject.lazyLink( listener ); + this.lazyLink( listener ); }, documentation: 'Adds a listener which will be called when the value changes. This method is like "link", but ' + 'without the current-value callback on registration. The listener takes two arguments, the new ' + @@ -157,7 +157,7 @@ returnType: VoidIO, parameterTypes: [ FunctionIO( VoidIO, [ parameterType ] ) ], implementation: function( listener ) { - this.phetioObject.unlink( listener ); + this.unlink( listener ); }, documentation: 'Removes a listener.' } Index: main/phet-io/js/phetioEngine.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- main/phet-io/js/phetioEngine.js (revision 371809713cf6b35ee3bb10c36663d95c8c19f1a0) +++ main/phet-io/js/phetioEngine.js (date 1599697961129) @@ -379,16 +379,16 @@ * @returns {ObjectIO} - instantiated IO Type * @public (phet-io-internal) */ - getWrapper( phetioID ) { - - // Support calls on phetioEngine as part of phetioInitialized callback, even though it has not been registered yet - // through phetioObjectAdded as part of the Tandem batch registration process. - if ( phetioID === this.tandem.phetioID ) { - return this.phetioWrapper; - } - assert && this.assertPhetioObjectFound( phetioID ); - return this.phetioObjectMap[ phetioID ].phetioWrapper; - } + // getWrapper( phetioID ) { + // + // // Support calls on phetioEngine as part of phetioInitialized callback, even though it has not been registered yet + // // through phetioObjectAdded as part of the Tandem batch registration process. + // if ( phetioID === this.tandem.phetioID ) { + // return this.phetioWrapper; + // } + // assert && this.assertPhetioObjectFound( phetioID ); + // return this.phetioObjectMap[ phetioID ].phetioWrapper; + // } /** * For convenience @@ -397,6 +397,9 @@ * @public */ getPhetioObject( phetioID ) { + if ( phetioID === this.tandem.phetioID ) { // TODO: improve this + return this; + } assert && this.assertPhetioObjectFound( phetioID ); return this.phetioObjectMap[ phetioID ]; } @@ -417,7 +420,7 @@ * @private */ phetioObjectAdded( phetioObject ) { - assert && assert( phetioObject.phetioWrapper, 'Can only be registered after initialization' ); + // assert && assert( phetioObject.phetioWrapper, 'Can only be registered after initialization' ); assert && assert( arguments.length === 1, 'Called with incorrect signature' ); assert && assert( phetioObject instanceof phet.tandem.PhetioObject, 'must be PhetioObject' ); assert && assert( phetioObject, 'Only non-falsy components should be registered' ); Index: main/forces-and-motion-basics/js/netforce/model/NetForceModelIO.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- main/forces-and-motion-basics/js/netforce/model/NetForceModelIO.js (revision 62bc71816d07895245265866a4aeecfef1386b07) +++ main/forces-and-motion-basics/js/netforce/model/NetForceModelIO.js (date 1599704243605) @@ -18,7 +18,7 @@ returnType: VoidIO, parameterTypes: [], implementation: function() { - this.phetioObject.reset(); + this.reset(); }, documentation: 'Resets the model', invocableForReadOnlyElements: false Index: main/sun/js/SliderIO.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- main/sun/js/SliderIO.js (revision f0f8a2d5a7ab7f261f1fdc64c0b44880558d240c) +++ main/sun/js/SliderIO.js (date 1599704243591) @@ -20,7 +20,7 @@ returnType: VoidIO, parameterTypes: [ BooleanIO ], implementation: function( visible ) { - this.phetioObject.setMajorTicksVisible( visible ); + this.setMajorTicksVisible( visible ); }, documentation: 'Set whether the major tick marks should be shown', invocableForReadOnlyElements: false @@ -30,7 +30,7 @@ returnType: VoidIO, parameterTypes: [ BooleanIO ], implementation: function( visible ) { - this.phetioObject.setMinorTicksVisible( visible ); + this.setMinorTicksVisible( visible ); }, documentation: 'Set whether the minor tick marks should be shown', invocableForReadOnlyElements: false Index: main/beers-law-lab/js/concentration/model/ConcentrationModelIO.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- main/beers-law-lab/js/concentration/model/ConcentrationModelIO.js (revision 58705d4f93efa1637353f937a5f8c1a50b4ed4f1) +++ main/beers-law-lab/js/concentration/model/ConcentrationModelIO.js (date 1599704243598) @@ -20,7 +20,7 @@ setSolutes: { parameterTypes: [ ArrayIO( SoluteIO ) ], returnType: VoidIO, - implementation: solutes => this.phetioObject.setSolutes( solutes ), + implementation: solutes => this.setSolutes( solutes ), documentation: 'Set which solutes are allowed for selection', invocableForReadOnlyElements: false } Index: main/scenery/js/nodes/ImageIO.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- main/scenery/js/nodes/ImageIO.js (revision c6b0dc1e26c0cd533f027ea725723c8b19709c60) +++ main/scenery/js/nodes/ImageIO.js (date 1599704243662) @@ -23,7 +23,7 @@ implementation: function( base64Text ) { const im = new window.Image(); im.src = base64Text; - this.phetioObject.image = im; + this.image = im; }, documentation: 'Set the image from a base64 string', invocableForReadOnlyElements: false Index: main/beers-law-lab/js/concentration/model/ShakerIO.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- main/beers-law-lab/js/concentration/model/ShakerIO.js (revision 58705d4f93efa1637353f937a5f8c1a50b4ed4f1) +++ main/beers-law-lab/js/concentration/model/ShakerIO.js (date 1599704243603) @@ -46,7 +46,7 @@ setValue: { returnType: VoidIO, parameterTypes: [ ObjectIO ], - implementation: valueStateObject => this.phetioObject.previousPosition.set( Vector2IO.fromStateObject( valueStateObject ) ), + implementation: valueStateObject => this.previousPosition.set( Vector2IO.fromStateObject( valueStateObject ) ), documentation: 'Load the values recorded in getState', invocableForReadOnlyElements: false } Index: main/axon/js/Action.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- main/axon/js/Action.js (revision fc83bd549a1b358061c8393b0409d8c7bde48bf8) +++ main/axon/js/Action.js (date 1599704243670) @@ -248,7 +248,7 @@ // Match `Action.execute`'s dynamic number of arguments implementation: function() { - this.phetioObject.execute.apply( this.phetioObject, arguments ); + this.execute.apply( this.phetioObject, arguments ); }, documentation: 'Executes the function the Action is wrapping.', invocableForReadOnlyElements: false ```

However, phet-io unit tests are failing because of the NodeIO properties.

samreid commented 4 years ago

On hold until https://github.com/phetsims/scenery/issues/1046 and possibly https://github.com/phetsims/scenery/issues/1047 are complete.

UPDATE FROM MK: and https://github.com/phetsims/scenery/issues/1082

samreid commented 4 years ago

One aspect of the patch was not blocked by the issues mentioned in the prior comment, so I decided to move forward with that change in order to (a) make that improvement and (b) prepare a more succinct patch since we may not return to this issue while it is fresh in our minds or before there is more churn in these files.

Here is the reduced patch after the above commits:

```diff Index: main/phet-io/js/phetioEngine.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- main/phet-io/js/phetioEngine.js (revision 46a3986178ad25b133afa31259b7fbe3182ec2b5) +++ main/phet-io/js/phetioEngine.js (date 1599731245340) @@ -373,23 +373,6 @@ return this.phetioObjectMap[ phetioID ].phetioType; } - /** - * Look up a component given a phetioID, or undefined if not registered - * @param {string} phetioID - * @returns {ObjectIO} - instantiated IO Type - * @public (phet-io-internal) - */ - getWrapper( phetioID ) { - - // Support calls on phetioEngine as part of phetioInitialized callback, even though it has not been registered yet - // through phetioObjectAdded as part of the Tandem batch registration process. - if ( phetioID === this.tandem.phetioID ) { - return this.phetioWrapper; - } - assert && this.assertPhetioObjectFound( phetioID ); - return this.phetioObjectMap[ phetioID ].phetioWrapper; - } - /** * For convenience * @param {string} phetioID @@ -397,6 +380,9 @@ * @public */ getPhetioObject( phetioID ) { + if ( phetioID === this.tandem.phetioID ) { // TODO: improve this + return this; + } assert && this.assertPhetioObjectFound( phetioID ); return this.phetioObjectMap[ phetioID ]; } @@ -417,7 +403,6 @@ * @private */ phetioObjectAdded( phetioObject ) { - assert && assert( phetioObject.phetioWrapper, 'Can only be registered after initialization' ); assert && assert( arguments.length === 1, 'Called with incorrect signature' ); assert && assert( phetioObject instanceof phet.tandem.PhetioObject, 'must be PhetioObject' ); assert && assert( phetioObject, 'Only non-falsy components should be registered' ); Index: main/phet-io/js/PhetioEngineIO.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- main/phet-io/js/PhetioEngineIO.js (revision 46a3986178ad25b133afa31259b7fbe3182ec2b5) +++ main/phet-io/js/PhetioEngineIO.js (date 1599731245335) @@ -33,7 +33,7 @@ const values = {}; for ( let i = 0; i < phetioIDs.length; i++ ) { const phetioID = phetioIDs[ i ]; - const wrapper = this.getWrapper( phetioID ); + const wrapper = this.phetioEngine.getPhetioObject( phetioID ); values[ phetioID ] = wrapper.getValue(); } return values; Index: main/phet-io/js/phetioCommandProcessor.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- main/phet-io/js/phetioCommandProcessor.js (revision 46a3986178ad25b133afa31259b7fbe3182ec2b5) +++ main/phet-io/js/phetioCommandProcessor.js (date 1599731127412) @@ -224,11 +224,13 @@ phet.phetio.phetioEngine.errorIfUndefined( phetioID ); // Load phetio from the namespace to avoid a module cycle - let wrapper = phet.phetio.phetioEngine.getWrapper( phetioID ); + let targetPhetioID = phetioID; + let targetObject = phet.phetio.phetioEngine.getPhetioObject( phetioID ); // If we are a LinkedElementIO, then forward the call onto the element that is being linked to. - if ( wrapper.phetioObject.phetioType === LinkedElementIO ) { - wrapper = phet.phetio.phetioEngine.getWrapper( wrapper.phetioObject.element.tandem.phetioID ); + if ( targetObject.phetioType === LinkedElementIO ) { + targetPhetioID = targetObject.element.tandem.phetioID; + targetObject = phet.phetio.phetioEngine.getPhetioObject( targetPhetioID ); } // Search up the chain to get the specified method. @@ -247,19 +249,19 @@ }; // {Object} - the method definition for an IO Type, see PropertyIO for examples - const methodSignature = getMethodSignature( wrapper.constructor, method ); + const methodSignature = getMethodSignature( targetObject.phetioType, method ); if ( !methodSignature ) { throw new Error( 'method not found: ' + phetioID + '.' + method ); } // Check for exact value of false instead of just truthiness because invocableForReadOnlyElements is often undefined - if ( wrapper.phetioObject.phetioReadOnly && methodSignature.invocableForReadOnlyElements === false ) { + if ( targetObject.phetioReadOnly && methodSignature.invocableForReadOnlyElements === false ) { throw new Error( 'Cannot invoke method \'' + method + '\' on read-only element \'' + phetioID + '\'' ); } // archetypes can't have methods called on them, see https://github.com/phetsims/phet-io-wrappers/issues/302 - if ( wrapper.phetioObject.phetioIsArchetype ) { + if ( targetObject.phetioIsArchetype ) { throw new Error( 'Cannot invoke method \'' + method + '\' on dynamic element archetype \'' + phetioID + '\'' ); } @@ -283,7 +285,7 @@ // Invoke the method. If it throws an error, it will be caught in handleSingleInvoke and returned to the client // See https://github.com/phetsims/phet-io/issues/941 - const result = methodSignature.implementation.apply( wrapper.phetioObject, args ); + const result = methodSignature.implementation.apply( targetObject, args ); // Serialize the result if possible. return methodSignature.returnType.toStateObject( result ); Index: main/tandem/js/PhetioObject.js IDEA additional info: Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP <+>UTF-8 =================================================================== --- main/tandem/js/PhetioObject.js (revision 9422eb38230c82c00645ce24c98665b97831dbd0) +++ main/tandem/js/PhetioObject.js (date 1599731129112) @@ -151,11 +151,6 @@ // @public (read-only) {Object} - see docs at DEFAULTS declaration this.phetioComponentOptions = DEFAULTS.phetioComponentOptions; - // @public (read-only) {ObjectIO|null} - assigned in initializePhetioObject - the instantiated IO Type. The phetioWrapper - // is the API layer between the wrapper and the phetioObject. It's used to call methods on this phetioObject from - // the wrapper frame. Will be null if this PhetioObject is never instrumented. - this.phetioWrapper = null; - // @private {boolean} - track whether the object has been initialized. This is necessary because initialization // can happen in the constructor or in a subsequent call to initializePhetioObject (to support scenery Node) this.phetioObjectInitialized = false; @@ -336,9 +331,6 @@ if ( PHET_IO_ENABLED && this.isPhetioInstrumented() ) { assert && Tandem.VALIDATION && assert( !this.phetioType.uninstrumented, 'cannot instantiate a phetioType that should not be instrumented' ); - - // @public (read-only phet-io-internal) - this.phetioWrapper = new this.phetioType( this, this.tandem.phetioID ); } this.tandem.addPhetioObject( this ); this.phetioObjectInitialized = true; @@ -551,7 +543,6 @@ if ( this.phetioObjectInitialized ) { this.tandem.removePhetioObject( this ); - this.phetioWrapper && this.phetioWrapper.dispose && this.phetioWrapper.dispose(); } // Dispose LinkedElements ```
samreid commented 4 years ago

I implemented a pattern for this as part of https://github.com/phetsims/tandem/issues/211. @zepumph can you review this part in isolation? See IOType.createWrapper and its usages.

zepumph commented 4 years ago

This makes a lot of sense. Thanks for taking this on. I'll stay assigned until those issues blocking issues are dealt with.

samreid commented 4 years ago

The title of this issue has been completed, since IOType is not a constructor for wrappers. However, now we would like to eliminate the wrapper completely, so I'll retitle the issue.

samreid commented 4 years ago

Implemented in the commits, and I moved https://github.com/phetsims/phet-io/issues/1712 to a side issue that I may need help on. @zepumph can you please review?

zepumph commented 4 years ago

Looks really good. I cleaned up "wrapper" terminology because we no longer think of IO Types as "wrappers" to the core type, and it is over-loaded with the other side of the cross-frame communication (wrapper side).

Closing, please reopen if there is anything else for you.