Skip to content

Instantly share code, notes, and snippets.

@SaicharanKandukuri
Last active November 5, 2022 12:37
Show Gist options
  • Save SaicharanKandukuri/9121d0cb22dd70db3b3764f37f8737da to your computer and use it in GitHub Desktop.
Save SaicharanKandukuri/9121d0cb22dd70db3b3764f37f8737da to your computer and use it in GitHub Desktop.
[null & 0 in javascript] code to show how strange relation between null & 0 works in javascript
/*
CODE to show how relation between null ( an object ) & 0 ( a Number ) works in JavaScript
code below is not fully implemented according to algorithm in ECMA-262 only the part where values of null & 0 satisfies are covered
REFER: https://262.ecma-international.org/5.1
(C) saicharankandukuri 2022
*/
const LOG = (buff) => console.log(buff);
/*
isPrimitive & toPrimitive functions are from https://stackoverflow.com/questions/52573030/is-there-a-way-to-call-toprimitive-in-javascript
thanks to https://stackoverflow.com/users/4151830/matthijs
*/
const isPrimitive = ( value ) =>
typeof value === 'object' ? value === null : typeof value !== 'function';
const toPrimitive = ( value, hint='default' ) => {
// if value is already a primitive, we're done
if( isPrimitive( value ) )
return value;
// if value[ Symbol.toPrimitive ] exists (is not undefined or null)
let method = value[ Symbol.toPrimitive ];
if( method != null ) { // using != instead of !== is intentional
// then call value[ Symbol.toPrimitive ]( hint )
let result = Reflect.apply( method, value, [ hint ] );
if( isPrimitive( result ) )
return result;
// if it doesn't return a primitive, do not fall back to legacy
// methods but just throw an error
} else {
// if value[ Symbol.toPrimitive ] doesn't exist, try the legacy
// valueOf() and toString() methods, in that order unless hint
// is 'string' in which case toString() is tried first.
//
// for these we need to be more garbage-tolerant: if the first
// legacy method is a non-function or returns a non-primitive,
// just ignore it and move on to the second one.
method = value[ hint === 'string' ? 'toString' : 'valueOf' ];
if( typeof method === 'function' ) {
let result = Reflect.apply( method, value, [] );
if( isPrimitive( result ) )
return result;
}
method = value[ hint === 'string' ? 'valueOf' : 'toString' ];
if( typeof method === 'function' ) {
let result = Reflect.apply( method, value, [] );
if( isPrimitive( result ) )
return result;
}
}
throw new TypeError("Cannot convert object to primitive value");
};
const ABSTRACT_RELATION = (x, y) => {
// REFER: https://262.ecma-international.org/5.1/#sec-11.8.5
// [NOTE]: LeftShift argument is skipped cause comparision results same either ways for null & 0
/*
If it is not the case that
both Type(px) is String and Type(py) is String,
then
*/
// to primitive a with hint Number => pa
let px = toPrimitive(x, Number);
let py = toPrimitive(y, Number);
if (typeof px && typeof py != 'string') {
// nx be the ToNumber
nx = Number(px);
ny = Number(py);
if (nx == ny) {
return false;
}
}
}
const EQUALITY_COMPARISION = (x, y) => {
// [NOT IMPLMENTED]: If Type(x) is the same as Type(y) cause type(null) != type(0)
// If Type(x) is the same as Type(y),
if (typeof x == null & typeof y == 'undefined') {
return true;
}
if (typeof x == 'undefined' & typeof y == null) {
return true;
}
// if x is object and y is Number or string || or the other way around
// return toPrimitive(<object_variable>, Hint Number) == non_object_variable
if ( typeof(x) == 'object' && (typeof y == 'number'|| typeof y == 'string')) {
LOG("HERE")
return toPrimitive(x, Number) == y;
}
if ( (typeof x == 'number'|| typeof x == 'string') && typeof y == 'object') {
return x == toPrimitive(y, Number) == x;
}
}
const LESS_THAN_OR_EQUAL = (x, y) => {
// https://262.ecma-international.org/5.1/#sec-11.8.3
/*
The Less-than-or-equal Operator ( <= )
The production RelationalExpression : RelationalExpression <= ShiftExpression is evaluated as follows:
Let lref be the result of evaluating RelationalExpression.
Let lval be GetValue(lref).
Let rref be the result of evaluating ShiftExpression.
Let rval be GetValue(rref).
Let r be the result of performing abstract relational comparison rval < lval with LeftFirst equal to false. (see 11.8.5).
If r is true or undefined, return false. Otherwise, return true.
*/
// [Note]: In algoritm the LeftShift is set to false which mean the comparision should run from right side
// Because of the comparision is with null & 0 and logically either ways gives same result that part is skipped
let r = ABSTRACT_RELATION(x,y)
return r == (true || 'undefined') ? false : true;
}
const GREATER_THAN_OR_EQUAL = (x, y) => {
// REFER: https://262.ecma-international.org/5.1/#sec-11.8.4
/*
The Greater-than-or-equal Operator ( >= )
The production RelationalExpression : RelationalExpression >= ShiftExpression is evaluated as follows:
Let lref be the result of evaluating RelationalExpression.
Let lval be GetValue(lref).
Let rref be the result of evaluating ShiftExpression.
Let rval be GetValue(rref).
Let r be the result of performing abstract relational comparison lval < rval. (see 11.8.5)
If r is true or undefined, return false. Otherwise, return true.
*/
let r = ABSTRACT_RELATION(x,y)
return r == (true || 'undefined') ? false : true;
}
const LESS_THAN = (x, y) => {
// REFER: https://262.ecma-international.org/5.1/#sec-11.8.1
/*
The Less-than Operator ( < )
The production RelationalExpression : RelationalExpression < ShiftExpression is evaluated as follows:
Let lref be the result of evaluating RelationalExpression.
Let lval be GetValue(lref).
Let rref be the result of evaluating ShiftExpression.
Let rval be GetValue(rref).
Let r be the result of performing abstract relational comparison lval < rval. (see 11.8.5)
If r is undefined, return false. Otherwise, return r.
*/
let r = ABSTRACT_RELATION(x,y)
if (r == undefined) {
return false;
}
return r;
}
const GREATER_THAN = (x, y) => {
// REFER: https://262.ecma-international.org/5.1/#sec-11.8.2
/*
The Greater-than Operator ( > )
The production RelationalExpression : RelationalExpression > ShiftExpression is evaluated as follows:
Let lref be the result of evaluating RelationalExpression.
Let lval be GetValue(lref).
Let rref be the result of evaluating ShiftExpression.
Let rval be GetValue(rref).
Let r be the result of performing abstract relational comparison rval < lval with LeftFirst equal to false. (see 11.8.5).
If r is undefined, return false. Otherwise, return r.
*/
let r = ABSTRACT_RELATION(x,y)
if (r == undefined) {
return false;
}
return r;
}
// LOG(toPrimitive(null, Number))
// LOG(ABSTRACT_RELATION(null, 0))
LOG("null == 0 \t->\t" + EQUALITY_COMPARISION(null, 0)) // null == 0
LOG("null >= 0 \t->\t" + GREATER_THAN_OR_EQUAL(null, 0)) // null >= 0
LOG("null <= 0 \t->\t" + LESS_THAN_OR_EQUAL(null, 0)) // null <= 0
LOG("null > 0 \t->\t" + GREATER_THAN(null, 0)) // null > 0
LOG("null < 0 \t->\t" + LESS_THAN(null, 0)) // null < 0
@SaicharanKandukuri
Copy link
Author

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment