Lanbo
Lanbo

Reputation: 15702

Commutative operator definition in Scala

Let's say I define some operators for my class like this:

class A {
    def +(f: Float) = /* ... */
}

val a: A = new A

This allows me to do a + 1f, easy enough. What if I want to enable the lib's user to be able to write 1f + a, too? How can I implement that?

Upvotes: 3

Views: 529

Answers (2)

Nikita Volkov
Nikita Volkov

Reputation: 43330

In Scala 2.9 you can import this implicit conversion:

implicit def floatPlusAExtender (x: Float) = 
  new {
    def + (a: A) = a + x
  }

and use it as you wanted. Since Scala 2.10 you better do this conversion like so:

implicit class FloatPlusAExtender (x: Float) {
  def + (a: A) = a + x
}

or even better like so:

implicit class FloatPlusAExtender (val x: Float) extends AnyVal {
  def + (a: A) = a + x
}

The last way is called Value Class and in difference to preceding two it provides this functionality with zero overhead. (Thanks, axel22) This is also the new stuff that comes with 2.10

Or you can just modify A like so:

class A {
  def + (x: Float) = /* ... */
  def +: (x: Float) = this + x
}

and use it like so:

1f +: a

The last approach is preferable.

Upvotes: 11

Malte Schwerhoff
Malte Schwerhoff

Reputation: 12852

One approach is the pimp-my-library-pattern:

class FloatWithPlusA(f: Float) {
  def +(a: A) = a + f
}

implicit def floatPlusA(f: Float): FloatWithPlusA =
  new FloatWithPlusA(f)

val a: A = new A
a + 1.0f  /* a.+(1.0f) */
1.0f + a  /* floatPlusA(1.0f).+(a) */

Another approach is adding a right-associative method, but with the obvious disadvantage that the syntax of the two operators varies:

class A {
  val f: Float = 1.0f

  def +(f: Float) = this.f + f
  def +:(f: Float) = this.f + f
}

val a: A = new A
a + 1.0f
1.0f +: a

Upvotes: 3

Related Questions