5

I have this Rational class that has a method for each operation (add,mult etc)

function Rational(nominator, denominator){
    this.nominator = nominator;
    this.denominator = denominator || 1;    
}

Rational.prototype = {
    mult: function(that) {
        return new Rational(
            this.nominator * that.nominator,
            this.denominator * that.denominator
            );
    },
    print: function() {
        return this.nominator + '/' + this.denominator;
    }
};

var a = new Rational(1,2),
    b = new Rational(3);

console.log( a.mult(b).print() ); // 3/2

Can I make it more "natural" e.g. to enable console.log( a * b ) ?

Paul Sweatte
  • 24,148
  • 7
  • 127
  • 265
Xlaudius
  • 1,757
  • 2
  • 13
  • 16
  • 4
    Javascript doesn't support operator overloading. You can replace `print()` with `toString` though. – georg Jun 14 '13 at 11:57
  • Some form of eval and string replacement would work, such as: console.log( Function("a * b".replace(" * b",".mult(b).print()" ) ) ) There are [one](http://stackoverflow.com/a/1390694/1113772) or [two](http://stackoverflow.com/questions/14147290/how-can-i-set-loop-imacros-by-javascript) questions about macros which may help. – Paul Sweatte Jun 19 '13 at 00:39

3 Answers3

9

You can't overload operators (read similar questions).

Moreover, a dedicated method like mult can be treated as a sign of good design (not only in Javascript), since changing the original operator behavior can confuse users (well, a rational number actually a good candidate for overloading).

You can change print to toString as user thg435 has suggested.

Going even further:

Rational.prototype = {
    mult : ... ,
    toString: ... ,
    valueOf: function() { return this.nominator / this.denominator; }
};

this will enable the a * b syntax (note: you don't operate on Rationals any more, but rather on primitives).

Community
  • 1
  • 1
emesx
  • 12,555
  • 10
  • 58
  • 91
  • That's what I thought too, however, it turned out to be wrong: try `new Rational(1,3).toString()`. – georg Jun 14 '13 at 12:12
  • No, it doesn't. If you define valueOf, string conversion will use that, and not your toString. So you get `0.3333` instead of `1/3`. – georg Jun 14 '13 at 12:19
  • 2
    I've asked a [question](http://stackoverflow.com/questions/17108265/make-toprimitive-conversion-depend-on-the-context) about this problem specifically. – georg Jun 14 '13 at 12:23
  • @thg435 ah, now I understand what you meant. Yes, when `valueOf` will return a primitive then `toString` might not get called, hence the `0.3333`. But the case for `toString` (in my answer) was to replace `print` in explicit calls – emesx Jun 14 '13 at 13:37
3

The closest you can get is some sort of operator aliasing, such as this:

/* Accepts a symbolic or string operator, returns a function which accepts numbers */
function operator(node)
  {
  //Mapping between string and symbol operators
  var map = {"mod": "%", "mult": "*", "div": "/", "plus": "+", "minus": "-"}

  //Return a function which applies the string or symbol operator to two numbers
  return Function("x,y", "return x" + (map[node] || node) + "y");
  }

// pass "*" to operator; pass 5,7 to returned function
var foo = operator("*")(5,7); 

// pass "plus" to operator; pass 3,2 to returned function
var bar = operator("plus")(3,2);

// pass "mod" to operator; pass 1,0 to returned function 
var baz = operator("mod")(1,0); 

console.log(["foo",foo,"bar",bar,"baz",baz]); //["foo", 35, "bar", 5, "baz", NaN]

References

Community
  • 1
  • 1
Paul Sweatte
  • 24,148
  • 7
  • 127
  • 265
0

As an idea, you can try to write a parser yourself so you write some thing like this:

console.log(R("a * b")); 

Where R is the function that converts a * b to a.mult(b) and then eval's this.

jbaylina
  • 4,408
  • 1
  • 30
  • 39