Table of Contents
- Operator-Overloading-JS
Operator-Overloading-JS#
This library enables simple operator overloading in Javascript code. This library has minimal runtime overheads, all overheads are done on loading time which is fair as that is done only when the system loads. Runtime performance is what is aimed for. We do AST Transformations during definition/load time to achieve the desired objective.
Installation##
This library is available for Node and Browser both. See the installation steps below:
Node Module (NPM)##
npm install operator-overloading --save
Browser (Bower)###
bower install operator-overloading --save
Sneak Peak Example##
Here is a quick sneak peak of the usage:
var overload = ;/*Here you are enabling overloading for this function scope only*/);
Overloadable Operators##
Following are the operators which can be overloaded with the desired overload function name:
S.No | Operator | Function Name | Operator Type |
---|---|---|---|
1 | + | __plus | Binary |
2 | == | __doubleEqual | Binary |
3 | === | __tripleEqual | Binary |
4 | || | __logicalOR | Binary |
5 | && | __logicalAND | Binary |
6 | | | __bitwiseOR | Binary |
7 | ^ | __bitwiseXOR | Binary |
8 | & | __bitwiseAND | Binary |
9 | != | __notEqual | Binary |
10 | !== | __notDoubleEqual | Binary |
11 | < | __lessThan | Binary |
12 | > | __greaterThan | Binary |
13 | <= | __lessThanEqual | Binary |
14 | >= | __greaterThanEqual | Binary |
15 | in | __in | Binary |
16 | instanceof | __instanceOf | Binary |
17 | << | __bitwiseLSHIFT | Binary |
18 | >> | __bitwiseRSHIFT | Binary |
19 | >>> | __zeroFillRSHIFT | Binary |
20 | - | __minus | Binary |
21 | * | __multiply | Binary |
22 | % | __modulus | Binary |
23 | / | __divide | Binary |
24 | u- | __unaryNegation | Unary |
25 | u+ | __unaryAddition | Unary |
26 | ~ | __bitwiseNOT | Unary |
27 | ++ | __increment | Unary |
28 | -- | __decrement | Unary |
29 | ! | __unaryNOT | Unary |
30 | += | __addAssign | Assignment |
31 | -= | __minusAssign | Assignment |
32 | *= | __multiplyAssign | Assignment |
33 | /= | __divideAssign | Assignment |
34 | %= | __modulusAssign | Assignment |
35 | <<= | __leftShiftAssign | Assignment |
36 | >>= | __rightShiftAssign | Assignment |
37 | >>>= | __zeroFillRightShiftAssign | Assignment |
38 | &= | __andAssign | Assignment |
39 | |= | __orAssign | Assignment |
40 | ^= | __xorAssign | Assignment |
41 | ** |
__exponent | Binary |
Design Consideration / Very IMP / Must Read##
It is very important that we DON'T modify the natural language. Hence the overloading feature will only be available in the specific code blocks where you intend to use it. Also marking them will make core readable for future developers giving them hint that this block has operator overloading enabled.
Also operator overloading only applies to lexical scope, no used or inherited objects are enriched. This is important for code security and assurance of natural operation.
Definig the context for using operator-overloading##
You need to specify a function and mark it such that operator overloading is enabled for code only in lexical scope of that function body.
Syntax 1: Simple declaration
var overload = ; var { //Here you can enjoy operator overloading.};//Nothing is overloaded outside the context of marked function above.//Run it;
Syntax 2: Anonymous declaration
var overload = ; ;//Nothing is overloaded outside the context of marked function above.
Syntax 3: Dual Flavour declaration
var overload = ; { return a + b;}; //Now get another function with operator overloading enabled.var addWithOverloadingEnabled = ; //Call with native operator results (Natural); //Call with overloaded operators;//Another way2 2; //Call with native operator results (Natural); //Original method will be untouched always.
Understanding restricted scope inheritance###
It is very important that we don,t write code which could mess up natural way of happings and make things harder for debug. Hence the functions we mark with enabled operator-overloading have completely different running contexts. Those functions can't use variables defined outside the overloaded function such that we don't accidently do stuff to the code which is intended to be executed in the natural way.
Example
var a = 222; //But if we have anything in global(node)/window(browser) scope that is accessibleglobalb = 333; console; //Output: 222console; //Output: 333 //Now this function has its own isolated execution context/scope.;
Example: If you need to access some objects, you can do:
var a = 222; console; //Output: 222 //Now this function has its own isolated execution context/scope.a; //Pass them as arguments ;)
Usage Guide##
There are two steps required to use operator overloading:
- Define overloading methods for operators intended to overload.
- Use them in a special context.
Objects should have desired methods for the operators to overload. The method you should override can be chosen from Overloadable Operators. For different operators its explained as follows:
Overloading binary/assignment operators###
For binary operators syntax is as follows:
NOTE: In the overloading functions this
is the RightValue(rval) and argument (leftValue)
is the LeftValue(lval). Ex: in 2 + 3
, lval = 2
and rval = 3
.
<AnyConstructor>prototype{ //Do magic...here //... //... return <whateverYouWantToDoAndReturnAsResult>;};
OR
<AnyObject>{ //Do magic...here //... //... return <whateverYouWantToDoAndReturnAsResult>;};
OR
{ this{ //Do magic...here //... //... return <whateverYouWantToDoAndReturnAsResult>; };};
EXAMPLE:
Numberprototype{ var rightValue = this; console; return leftValue + rightValue;}; console; //Output: 55 ;
Overloading unary operators###
There is no argument passed in these functions as there is no other operand. the operand the unary operator is applied is available in this
object.
<AnyConstructor>prototype{ var operand = this; //Do magic...here //... //... return <whateverYouWantToDoAndReturnAsResult>;};
OR
<AnyObject>{ var operand = this; //Do magic...here //... //... return <whateverYouWantToDoAndReturnAsResult>;};
OR
{ this{ var operand = this; //Do magic...here //... //... return <whateverYouWantToDoAndReturnAsResult>; };};
Using the overloaded operators###
Whatever function is transformed via overload
is eligible for operator overloading.
var a = 222; console; //Output: 222 //Now this function has its own isolated execution context/scope.a; //Pass them as arguments ;)
Examples##
Some examples:
Simple Student Constructor###
The same example we have shown above.
var overload = ;/*Here you are enabling overloading for this function scope only*/);
Function Callback Fun###
Just a fun way to pass callbacks. Just a demonstration experiment.
var overload = ; //Specify behavior for '>>'Functionprototype { return ;}; //Fun time;
Instanceof for Serialized objects###
Check if serialised object is instance of a particular constructor.
var overload = ; { var self = this; thistype = thisconstructorname; thisname = name; thisage = age; thisdob = dob; thisemail = email; this { return JSON; }; //Overload. We are overloading User also as operation will also be performed on User constructor as an operand. this__instanceOf = User { if obj instanceof String || typeof obj === 'string' obj = JSON; //compatibility for serialized JSON too. return objtype === 'User'; };} { var self = this; thistype = thisconstructorname; thisuser = user; thistitle = title; thisdescription = description; this { return JSON; }; //Overload. We are overloading User also as operation will also be performed on User constructor as an operand. this__instanceOf = Issue { if obj instanceof String || typeof obj === 'string' obj = JSON; //compatibility for serialized JSON too. return objtype == 'Issue'; };} var user1 = 'Kushal' 22 'email@domain.com';var issue1 = user1 'Life is not fun!' 'Operator overloading in required in JS.'; var sUser1 = user1;var sIssue1 = issue1; console;console; console; //Output: falseconsole; //Output: falseconsole; //Output: falseconsole; //Output: false //try out with overloadingsUser1 sIssue1 User Issue;
Playground###
Just a rough playground.
var overload = ; //An example Constructor Class { var _this = this; thisval = val; this { console; leftOperandval += _thisval; return this; }; this { console; return _thisval == leftOperandval; }; this { console; return _thisval === leftOperandval; };} //We can put in Native types tooStringprototype { return leftOperand + " <added> " + this;}; //Number exampleNumberprototype { console; return leftOperand + this;}; var v1 = 10;var v2 = 20;var v3 = 30; //That's how you do it. Ity has its own context scopevar run = ; //Do this to enable operator overloading in this function. We don't recommend global enablement as that would be confusing. //This will be normal operation as defined in JS.console; ;
Dev Tips##
For all those who are contributing or ones who wants to see debug info can run via:
OVERLOAD_DEBUG=true node <program>.js
Above will print the AST and transformed code.
Backwards Compatibility##
For pre 0.5 backwards compatibility do require('operator-overloading/global')
and enableOverloading
will work as expected, however this is not recommended as it pollutes a host object.
Revision History##
- Version 0.1: The first poc release overloading only +-*/ operators.
- Version 0.2: Added support for all binary operators and unary operators.
- Version 0.3: Updated AST Traversal to enable inline inner functions.
- Version 0.4: Added support for assignment operators.
- Version 0.5: Removed pollution of host object.