-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Discuss/document/eliminate/improve validateOptionsOnValidateValue #207
Comments
For the benefit of anyone else following this, |
Now that I understand this.... Here's a proposal. Rename Usages outside of Property would look like this, with Validator.validate( options.initialNumberOfParticles, {
isValidValue: value => ...
} );
this.location = Validator.validate( options.location, {
valueType: Vector2
} ); Usages inside of Property, or anything else that calls Validator.validate( someValue, {
...,
validateOptions: false
} ); In Property, I can't think of any reason to be validating the Validator options more than once. So remove assert && Validator.validateOptions( this.validatorOptions );
this.validatorOptions = Validator.pickOptions( options, {
// Validator options only need to be validate once, which we did above.
// Set to false to improve performance of subsequent Validator.validate calls.
validateOptions: false
} ); |
So far we have been treating What if instead we added an
and in Property and Emitter we could use the nested options pattern like:
Because in those cases we wouldn't want to revalidate the validator each time the Property value changed, or each time the Emitter was emitted. |
It may be even clearer to segregate these further. For instance, if the default is to validate the validation options, we could have: validate(value,validator){
validateValidator(validator);
validateValue(value,validator);
} Then sites that want to opt out of validating the validator each time (such as Property or Emitter) could use |
I'm not sure what is better between the preceding two comments. @zepumph what do you think? |
I really like that all logic is islotated in Index: js/ValidatorDef.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- js/ValidatorDef.js (revision e9824fde1639d689700a3dad0c283d9688a6eb21)
+++ js/ValidatorDef.js (date 1568935595220)
@@ -71,19 +71,6 @@
// {function(PhetioType is a
'phetioType'
-
- /**************************************
- * Additionally, validation will always check the validator itself. However, for types like Property and Emitter,
- * re-checking the validator every time the Property value changes or the Emitter emits wastes time. Hence cases like
- * those can opt-out by specifying:
- *
- * validateOptionsOnValidateValue: false
- *
- * Note: this should not be a key in VALIDATOR_KEYS because the keys are reserved for checking the value itself,
- * see implementation and usage of containsValidatorKey. Our "definition" of a validator is the makeup of the keys
- * above, validateOptionsOnValidateValue is more of a meta-option that is not for checking the value itself, but
- * whether to check the validator at the same time.
- *********************/
];
const ValidatorDef = {
@@ -233,10 +220,19 @@
*/
isValueValid( value, validator, options ) {
- options = options || ASSERTIONS_FALSE;
+ options = _.extend( {
+
+ // {boolean} - By default validation will always check the validity of the validator itself. However, for types like
+ // Property and Emitter re-checking the validator every time the Property value changes or the Emitter emits
+ // wastes cpu. Hence cases like those can opt-out
+ validateOptions: true,
+
+ // if true, throw an assertion "instead" of waiting to return a boolean
+ assertions: false
+ }, options );
// Use the same policy for whether to throw assertions when checking the validator itself.
- if ( validator.validateOptionsOnValidateValue !== false && !axon.ValidatorDef.isValidValidator( validator, options ) ) {
+ if ( options.validateOptions !== false && !axon.ValidatorDef.isValidValidator( validator, options ) ) {
assert && options.assertions && assert( false, 'Invalid validator' );
return false;
}
Index: js/Action.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- js/Action.js (revision e9824fde1639d689700a3dad0c283d9688a6eb21)
+++ js/Action.js (date 1568935595224)
@@ -20,6 +20,8 @@
const ValidatorDef = require( 'AXON/ValidatorDef' );
// constants
+ const VALIDATE_OPTIONS_FALSE = { validateOptions: false };
+
// Simulations have thousands of Emitters, so we re-use objects where possible.
const EMPTY_ARRAY = [];
assert && Object.freeze( EMPTY_ARRAY );
@@ -122,9 +124,6 @@
for ( let i = 0; i < parameters.length; i++ ) {
const parameter = parameters[ i ]; // metadata about a single parameter
- assert && assert( parameter.validateOptionsOnValidateValue === undefined,
- 'Action sets its own validateOptionsOnValidateValue for each argument type'
- );
assert && assert( Object.getPrototypeOf( parameter ) === Object.prototype,
'Extra prototype on parameter object is a code smell' );
@@ -147,11 +146,6 @@
assert && assert( PARAMETER_KEYS.includes( key ), 'unrecognized parameter key: ' + key );
}
- // TODO: is this taking up too much memory? Does this create too much garbage? https://github.com/phetsims/axon/issues/257
- parameters[ i ] = _.extend( {
- validateOptionsOnValidateValue: false
- }, parameter );
-
// Changing after construction indicates a logic error.
assert && Object.freeze( parameters[ i ] );
@@ -229,11 +223,11 @@
);
for ( let i = 0; i < this._parameters.length; i++ ) {
const parameter = this._parameters[ i ];
- validate( arguments[ i ], parameter );
+ validate( arguments[ i ], parameter, VALIDATE_OPTIONS_FALSE );
// valueType overrides the phetioType validator so we don't use that one if there is a valueType
if ( parameter.phetioType && !this._parameters.valueType ) {
- validate( arguments[ i ], parameter.phetioType.validator );
+ validate( arguments[ i ], parameter.phetioType.validator, VALIDATE_OPTIONS_FALSE );
}
}
}
Index: js/validate.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- js/validate.js (revision e9824fde1639d689700a3dad0c283d9688a6eb21)
+++ js/validate.js (date 1568935385077)
@@ -17,15 +17,16 @@
* If assertions are enabled, assert out if the value does not adhere to the validator. No-op without assertions.
* @param {*} value
* @param {ValidatorDef} validator
+ * @param {Object} [options] - see ValidatorDef.isValueValid
* @returns {*} - returns the input value for chaining
* @public
*/
- const validate = ( value, validator ) => {
+ const validate = ( value, validator, options ) => {
if ( assert ) {
// Throws an error if not valid
- ValidatorDef.isValueValid( value, validator, { assertions: true } );
+ ValidatorDef.isValueValid( value, validator, _.extend( { assertions: true }, options ) );
}
return value;
};
Index: js/Property.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- js/Property.js (revision e9824fde1639d689700a3dad0c283d9688a6eb21)
+++ js/Property.js (date 1568935595217)
@@ -19,6 +19,9 @@
const validate = require( 'AXON/validate' );
const ValidatorDef = require( 'AXON/ValidatorDef' );
+ // constants
+ const VALIDATE_OPTIONS_FALSE = { validateOptions: false };
+
// variables
let globalId = 0; // autoincremented for unique IDs
@@ -46,10 +49,6 @@
// cycles may pollute the data stream. See https://github.com/phetsims/axon/issues/179
reentrant: false,
- // By default, check the options once in the constructor, not on each subsequent value validation, to improve
- // performance in requirejs mode
- validateOptionsOnValidateValue: false
-
// Property also supports validator options, see ValidatorDef.VALIDATOR_KEYS.
}, options );
@@ -136,7 +135,7 @@
}
ValidatorDef.validateValidator( validator );
- this.validate = value => validate( value, validator );
+ this.validate = value => validate( value, validator, VALIDATE_OPTIONS_FALSE );
// validate the initial value
this.validate( value ); |
That looks great, thanks! |
Excellent! Committed above. @pixelzoom thank you so much for this solution. I'm really happy with it. It is clean and precise, unlike the last one. Closing |
In #189 there was a lot of confusion about
validateOptionsOnValidateValue
. It is documented like so:@pixelzoom is this sufficient? Do you want further investigation about simplifying/renaming/removing this option?
The text was updated successfully, but these errors were encountered: