Is it possible to create custom operators in JavaScript?
Asked Answered
I

11

47

During the Math classes we learned how to define new operators. For example:

(ℝ, ∘), x ∘ y = x + 2y

This defines law. For any real numbers x and y, x ∘ y is x + 2y.

Example: 2 ∘ 2 = 2 + 4 = 6.


Is possible to define operators like this in JavaScript? I know that a function would do the job:

function foo (x, y) { return x + 2 * y; }

but I would like to have the following syntax:

var y = 2 ∘ 2; // returns 6

instead of this:

var y = foo(2, 2);

Which is the closest solution to this question?

Illusionism answered 22/12, 2013 at 10:36 Comment(5)
Another name for this is infix function notation - the answer is no, you cannotCorinnecorinth
You could try to exploit valueOf with existing operators, but that's about it in JavaScript.Sharpeyed
I would argue that it's a really bad idea to want to define an operator for which the symbol does not feature on my keyboardCorinnecorinth
No. You can't do that in JavaScript. However, you can do it in Haskell. First line: infixl 6 ∘. Second line: x ∘ y = x + 2 * y.Spin
Technically you can, by writing your own lexical parser and defining your own name of script type in the <script> block. This technique is used quite widely. Some well-known examples include Google Traceur.Jereme
U
31

The short answer is no. ECMAScript (the standard JS is based on) does not support operator overloading.

As an aside, in ECMAScript 7, you'll be able to overload a subset of the standard operators when designing custom value types. Here is a slide deck by language creator and Mozilla CTO Brendan Eich about the subject. This won't allow arbitary operators, however, and the overloaded meaning will only be applied to value types. <- haha that ended up not happening.

It is possible to use third party tools like sweet.js to add custom operators though that'd require an extra compilation step.

I've answered with a solution from outside JavaScript using esprima - this is changing JavaScript and extending it, it's not native.

Urology answered 22/12, 2013 at 10:39 Comment(9)
Can you add a reference? How will I define such an operator after it will be implemented?Chromatolysis
I doubt any version of ECMAScript comes with the ability to define new symbolic operators - that's normally reserved for languages like haskell. I suspect it'll only come with operator overloadingCorinnecorinth
@Corinnecorinth what Haskell does is not magic. There is no trouble introducing backticks for infix notation in JS :) However yes, the current proposal discusses operator overloading.Urology
@BenjaminGruenbaum: Sure, it's not magic, but defining symbolic operators is a slippery slope to perlCorinnecorinth
I see no mention on the ECMAScript page on value objects suggesting that user code can declare new value typesCorinnecorinth
@Corinnecorinth that page is old and messy. That's why I linked to the slide-deck. I can link to TC39 meetings if you prefer but reading transcripts doesn't sound like too much fun to me so I didn't :)Urology
@BenjaminGruenbaum as shown on page 3 of the linked slide deck slideshare.net/BrendanEich/value-objects/3 only a subset of the existing operators will be overloadable; new ones cannot be added.Epigenesis
@Epigenesis Correct, that has been said in a comment here before. My answer does not directly answer the question (it talks about overloading and not adding new operators), if you think it's phrased in a confusing way - feel free to edit it. I've created a short script with esprima and escodegen that allows extneding the syntax like this by the way I'll add it later. Hi by the way - it's good to see you here :) If you have any relevant TC39 or esdiscuss threads to link to here that'd be great (I couldn't find any).Urology
@BenjaminGruenbaum good to see you here too :). I've edited that paragraph for clarity.Epigenesis
K
8

Given the somewhat new tagged template literals feature that was added in ES6 one can create custom DSLs to handle embedded expressions such as these including different algebraic symbols.

ex. (run in stackblitz)

function math(strings, x, y) {
  // NOTE: Naive approach as demonstration

  const operator = strings[1].replace(/\s/gi, "");

  if (operator == "∘") {
    return x + 2 * y;
  }
  else if (operator == "^") {
    return Math.pow(x, y);
  }
  else {
    return `Unknown operator '${operator}'`;
  }
}

console.log(math`${2} ∘ ${2}`)

Note that since tagged template literals don't necessarily return strings as results they can return more complex intermediate AST like structures to build up an expression that can then be further refined and then interpreted while keeping close to the domain specific language at hand. I haven't found any existing library that does this yet for Javascript but it should be an interesting and quite approachable endeavor from what it appears from what I know of tagged template literals and usage in such places as lit-html.

Knighton answered 14/4, 2019 at 3:33 Comment(0)
T
5

No. You can't do that in JS.

The closest you can have IMO is to implement your own object which has a chainable interface, aka "fluent" syntax. That way you can operate as if you were speaking out in sequence.

var eq = new YourEquationObject();

// Then operate like 1 - 2 * 3
eq.add(1).sub(2).mul(3);

Details are up to you though. Just giving out an idea.

Traduce answered 22/12, 2013 at 10:41 Comment(0)
C
5

You can add pseudo-operators via methods on Number.prototype:

Object.defineProperty(Number.prototype, 'myOp', {
    value: function(that) {
        return this + 2 * that;
    }
});

Then all of this syntax will work

alert( (2).myOp(2) )
alert( 2 .myOp(2) )
alert( 2..myOp(2) )
alert( 2.0.myOp(2) )

2.myOp(2) does not work because the period is treated as a decimal point

Corinnecorinth answered 22/12, 2013 at 11:8 Comment(0)
S
3

No. JavaScript does not support operator overloading . but you can make a class method for doing this

var mathClass = function(value){
   this.value = value;
}

mathClass.prototype.toLaw = function(){
   return 2 * this.value;
}

var y = new mathClass(2)
2 + y.toLaw(); //2 + 2 * y
Squeal answered 22/12, 2013 at 10:43 Comment(1)
You can go one step further and add these to Number.prototype, as in my answerCorinnecorinth
B
2

Read the comments below the answer.

Apparently you can't. Here is something close :

function exec(input) {
    return Function(
        'return ' + input.replace(/∘( *[\d.]+)/g, '+ 2 * $1') + ';'
    )();
}

exec('2 ∘ 2'); // 6
Bachman answered 22/12, 2013 at 10:46 Comment(5)
(1 + 1) ∘ (1 + 1) will ruin your dayCorinnecorinth
Paperscript does this quite throughlyCorinnecorinth
@Corinnecorinth Good approach, but '2 ∘ 2' is a string. I would like not to be a string.Chromatolysis
@イオニカビザウ: The idea is you mark a script tag as language="myjavascript", and then have a small script to translate your code into raw javascript at runtineCorinnecorinth
To do it properly, you'll want a javascript AST library like acorn or esprima. If you want to add new symbolic operators, you'll probably have to tweak the parser a littleCorinnecorinth
D
2

Set of compiled to JS languages support custom operators.

I would highlight ReasonML (ocaml-syntax-readable-by-js-folks) and Bucklescript (ocaml-to-js-compiler) which makes custom operators look neat:

For example an operator to concatenate strings can look like:

let (>|<) = (list, seperator) => Belt.List.reduce(list, "", (a, b) => a ++ seperator ++ b);

which can then be used like:

[Styles.button, Media.Classes.atLeastTablet] >|< " "

The downside of all this is the fact it has to be written in such compiled-to-js language, and it comes with lots of pros and cons, but usually those languages have the appeal of tons of nice syntactic sugar you don't get in js/ts

Dee answered 25/5, 2020 at 19:8 Comment(0)
A
1

The slightly longer then the short one is that Yes you can, but its a bit more involved then what you did in Math class

To extend the language with new constructs you can use a transformer like http://esprima.org/ or any of the others. You need to define your syntax, write the parser to parse your statement and finally add the actual code to do the math parts. When these parts is in place you have made a new language that works just as javascript but with the added support of the operator.

Its really not that hard to add new syntax, here is facebooks example how they add => arrow function syntax

https://github.com/facebook/jstransform/blob/master/visitors/es6-arrow-function-visitors.js

Alston answered 22/12, 2013 at 10:54 Comment(0)
M
0

I was asking this question too, and here's my answer:

function myCustomOperation(string){
var res = String.fromCharCode(9762);
var thing = string.replace(/☢/g," + 10 + ");
thing=thing.replace(/☣/g," * 2 + ");
thing=thing.replace(/☠/g," / 3 * ");
return [eval(thing),string+" = "+eval(thing)];
};
var thing = myCustomOperation("

3 ☠ 4

");
document.write(thing[1]);
Mensural answered 14/1, 2016 at 21:50 Comment(0)
T
0

There are several tools, compilers, or language extensions providing such a possibility, and even using emojis and other stuff, that are uncommon in JavaScript itself. sweet.js is the closest one I can remember, and also another JavaScript compiled tool might be useful.

Terrieterrier answered 5/9, 2022 at 4:30 Comment(0)
P
0

Since JS doesn't allow to define custom operators now and if you don't want to use complex solutions you can take a look on extending Number class with needed functions (operators), for instance:

Number.prototype.o = function(y) {
  return this + 2 * y;
};

// 2 ∘ 2

let n = 2;
const r1 = n.o(2);
console.log(r1); // Prints: 6

// OR

const r2 = (2).o(2);
console.log(r2); // Prints: 6

With this approach you can make complex math expressions by chaining operators each after another:

Number.prototype.pow = function(exponent) {
  return Math.pow(this,  exponent);
};

Number.prototype.sqrt = function() {
  return Math.sqrt(this);
};

// √((2 ∘ 2)² - 11)

const r3 = (((2).o(2)).pow(2) - 11).sqrt();
console.log(r3); // Prints: 5
Palish answered 24/3, 2023 at 11:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.