Are Variable Operators Possible?

JavascriptVariablesOperatorsOperator KeywordDynamic Variables

Javascript Problem Overview


Is there a way to do something similar to either of the following:

var1 = 10; var2 = 20;
var operator = "<";
console.log(var1 operator var2); // returns true

-- OR --

var1 = 10; var2 = 20;
var operator = "+";
total = var1 operator var2; // total === 30

Javascript Solutions


Solution 1 - Javascript

Not out of the box. However, it's easy to build by hand in many languages including JS.

var operators = {
    '+': function(a, b) { return a + b },
    '<': function(a, b) { return a < b },
     // ...
};

var op = '+';
alert(operators[op](10, 20));

You can use ascii-based names like plus, to avoid going through strings if you don't need to. However, half of the questions similar to this one were asked because someone had strings representing operators and wanted functions from them.

Solution 2 - Javascript

We can implement this using eval, since we are using it for operator checking.

var number1 = 30;
var number2 = 40;
var operator = '===';

function evaluate(param1, param2, operator) {
  return eval(param1 + operator + param2);
}

if (evaluate(number1, number2, operator)) {}

in this way we can use dynamic operator evaluation.

Solution 3 - Javascript

I believe you want a variable operator. here's one, created as object. you can change the current operation by changing:

[yourObjectName].operation = "<" //changes operation to less than


function VarOperator(op) { //you object containing your operator
	this.operation = op;
	
	this.evaluate = function evaluate(param1, param2) {
		switch(this.operation) {
			case "+":
				return param1 + param2;
			case "-":
				return param1 - param2;
			case "*":
				return param1 * param2;
			case "/":
				return param1 / param2;
			case "<":
				return param1 < param2;
			case ">":
				return param1 > param2;
		}
	}
}

//sample usage:
var vo = new VarOperator("+"); //initial operation: addition
vo.evaluate(21,5); // returns 26
vo.operation = "-" // new operation: subtraction
vo.evaluate(21,5); //returns 16
vo.operation = ">" //new operation: ">"
vo.evaluate(21,5); //returns true

Solution 4 - Javascript

You can use the eval() function, but that is not a good idea. I think the better way is writing functions for your operators like this:

var addition = function(first, second) {
   return first+second;
};

var subtraction = function(first, second) {
   return first-second;
};

var operator = addition;

alert(operator(12, 13));

var operator = subtraction;

alert(operator(12, 13));

Solution 5 - Javascript

You can't overload operators in JavaScript. You can off course use functions to help

var plus = function(a, b) {
    return a + b;
};

var smaller = function(a, b) { 
    return a < b;
};

var operator = plus;
var total = operator(a, b);
operator = smaller;
if(operator(var1, var2)){ /*do something*/ }

Solution 6 - Javascript

From another answer I recently posted, this is in V8 and I think JavaScriptCore, but not Firefox and it's not spec. Since you can trap the operation and the comparators you can implement operator native overloading in most situations with a bit of work.

var actions = [];
var overload = {
  valueOf: function(){
    var caller = arguments.callee.caller;
    actions.push({
      operation: caller.name,
      left: caller.arguments[0] === this ? "unknown" : this,
      right: caller.arguments[0]
    });
    return Object.prototype.toString.call(this);
  }
};
overload.toString = overload.valueOf;
overload == 10;
overload === 10;
overload * 10;
10 / overload;
overload in window;
-overload;
+overload;
overload < 5;
overload > 5;
[][overload];
overload == overload;
console.log(actions);

Output:

[ { operation: 'EQUALS',
    left: overload,
    right: 10 },
  { operation: 'MUL',
    left: overload,
    right: 10 },
  { operation: 'DIV',
    left: 'unknown',
    right: overload },
  { operation: 'IN',
    left: overload,
    right: DOMWindow },
  { operation: 'UNARY_MINUS',
    left: overload,
    right: undefined },
  { operation: 'TO_NUMBER',
    left: overload,
    right: undefined },
  { operation: 'COMPARE',
    left: overload,
    right: 5 },
  { operation: 'COMPARE',
    left: 'unknown',
    right: overload },
  { operation: 'ToString',
    left: 'unknown',
    right: overload } ]

At this point you have all the inputs and the operation so the remaining part is the result of the operation. The receiver of the operation will get a primitive value, either string or number, and you can't prevent this. If it's not an arbitrary reciever, say an instance of the class you've operator overloaded, you can handle various get/set traps to intercept the incoming value/prevent overwriting. You can store the operands and operation in some central lookup and use a simple method to trace a primitive value back to the operation which produced it, and then create whatever logic you want to do your custom operation. Another method which would allow arbitrary receivers which could later be reconstituted into complex forms would be in encoding the data into the primitive value so that it can be reversed back into your complex class. Like say an RGB value of 3 distinct 8bit integers (255,255,255) could be be converted into a single number on the get end and the receiver end could trivial convert it back into its complex components. Or for more complex data you could even return a JSON serialized string.

Having access to Harmony Proxies (Firefox6+, Nodejs with flag) makes this whole process immensely easier, as you can create trapping proxies on basically everything and introspect the entire process from end to end and do whatever you want. The operand instances of your data/class, the valueOf/toString/getters of every possible value the internal engine may access, any receiver object you have pre-awareness of, and even trap arbitrary receivers in the case of with(trappingProxy){ "all variable lookup, creation, and setting in here invokes traps on our proxy"; }

Solution 7 - Javascript

A bit newer approach. It can be done pretty decent using currying:

const calculate = a => str => b => {switch(str) {
  case '+': return a + b
  case '-': return a - b
  case '/': return a / b
  case '*': return a * b
  default: return 'Invalid operation'
}}

const res = calculate(15)('*')(28)

console.log('15 * 28 =', res)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGaryView Question on Stackoverflow
Solution 1 - Javascriptuser395760View Answer on Stackoverflow
Solution 2 - JavascriptManuView Answer on Stackoverflow
Solution 3 - JavascriptdannielView Answer on Stackoverflow
Solution 4 - JavascriptManuel RicharzView Answer on Stackoverflow
Solution 5 - JavascriptcellcortexView Answer on Stackoverflow
Solution 6 - Javascriptuser748221View Answer on Stackoverflow
Solution 7 - JavascriptulouView Answer on Stackoverflow