Skip to content
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

Refactor to simplify null or undefined checks #471

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

Mini-ghost
Copy link
Contributor

Currently, the methods nonNullish, nonNullishAsync, nullish, and nullishAsync determine if input is null or undefined using the following approach:

input === null || input === undefined

According to the ECMAScript specification mentioned in:

13.11.1 Runtime Semantics: Evaluation
EqualityExpression : EqualityExpression == RelationalExpression

  1. Let lref be ? Evaluation of EqualityExpression.
  2. Let lval be ? GetValue(lref).
  3. Let rref be ? Evaluation of RelationalExpression.
  4. Let rval be ? GetValue(rref).
  5. Return ? IsLooselyEqual(rval, lval).

The specification for IsLooselyEqual is as follows:

7.2.14 IsLooselyEqual ( x, y )
The abstract operation IsLooselyEqual takes arguments x (an ECMAScript language value) and y (an ECMAScript language value) and returns either a normal completion containing a Boolean or a throw completion. It provides the semantics for the == operator. It performs the following steps when called:

  1. If Type(x) is Type(y), then
    a. Return IsStrictlyEqual(x, y).
  2. If x is null and y is undefined, return true.
  3. If x is undefined and y is null, return true.
    ...ellipsis

In points two and three, we find that using null == undefined yields true. Therefore, we can simplify our check as follows:

- input === null || input === undefined
+ input == null

It perhaps makes the code more concise. If there are any concerns, we are eager to hear your thoughts.

@fabian-hiller
Copy link
Owner

I think for Valibot I prefer an explicit check for both values. Also, as far as I know, === is much faster than ==. But I plan to work on another library with a similar external API as Valibot, which is completely focused on bundle size. There I could imagine this change to reduce the source code.

@fabian-hiller fabian-hiller self-assigned this Mar 8, 2024
@fabian-hiller fabian-hiller added the question Further information is requested label Mar 8, 2024
@Mini-ghost
Copy link
Contributor Author

You are absolutely correct, it should indeed align with your preference, and there truly isn't a right or wrong choice here. I believe there is not much difference between the two methods in terms of performance and bundle size. I merely noticed this approach being frequently used in various libraries, which is why I attempted to initiate this PR.

Thank you very much for your response.

@fabian-hiller
Copy link
Owner

Thank you for your response! I will keep this PR open for now. I will look into it when I start working on the other library I mentioned.

@nakanoasaservice
Copy link

For reference, I have included a simple code snippet to compare execution speeds. In my environment, while there was hardly any difference observed when running on Node, on Bun, the '===' operation was found to be 2.8 times slower.

function useEqualityOp(x) {
	return x == null;
}

function useStrictEqualityOp(x) {
	return x === null && x === undefined;
}

// Test data
const testData = [null, undefined, 0, false, "", {}, []];
const iterations = 10000000;

// Measure the execution time of ==
const start1 = performance.now();
for (let i = 0; i < iterations; i++) {
	for (let j = 0; j < testData.length; j++) {
		useEqualityOp(testData[j]);
	}
}
const end1 = performance.now();
console.log("==:", end1 - start1, "milliseconds");

// Measure the execution time of ===
const start2 = performance.now();
for (let i = 0; i < iterations; i++) {
	for (let j = 0; j < testData.length; j++) {
		useStrictEqualityOp(testData[j]);
	}
}
const end2 = performance.now();
console.log("===:", end2 - start2, "milliseconds");

Node v20.11.1:

==: 476.43787499999996 milliseconds
===: 474.964833 milliseconds

Bun v1.0.26:

==: 293.179 milliseconds
===: 819.7497920000001 milliseconds

@fabian-hiller
Copy link
Owner

Thank you for your research!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants