Scala Implicit conversion function name function.

I work with a class class of complex classes in Scala and would like to create an add function that works between complex numbers, doubles and ints. The following is a simple example of a working solution:

case class Complex(re: Double, im: Double) implicit def toComplex[A](n: A)(implicit f: A => Double): Complex = Complex(n, 0) implicit class NumberWithAdd[A](n: A)(implicit f: A => Complex) { def add(m: Complex) = Complex(n.re + m.re, n.im + m.im) } 

Note. I intentionally do not include the add function in the complex case class. Using the above, I can do all of this:

 scala> val z = Complex(1, 2); val w = Complex(2, 3) z: Complex = Complex(1.0,2.0) w: Complex = Complex(2.0,3.0) scala> z add w res5: Complex = Complex(3.0,5.0) scala> z add 1 res6: Complex = Complex(2.0,2.0) scala> 1 add z res7: Complex = Complex(2.0,2.0) 

I would like to use '+' instead of 'add, but this does not work. I get the following error:

 Error:(14, 4) value + is not a member of A$A288.this.Complex z + 1 ^ 

Both z + w and 1 + z still work.

What would I like to know why changing a function name from 'add' to '+' violates this? Is there an alternative way to get this functionality (without just adding the add function to the complex case class)? Any help would be appreciated.

Change - Motivation

I play with monoids and other algebraic structures. I would like to be able to generalize the "... WithAdd" function to automatically work for any class with the corresponding monoid:

 trait Monoid[A] { val identity: A def op(x: A, y: A): A } implicit class withOp[A](n: A)(implicit val monoid: Monoid[A]) { def +(m: A): A = monoid.op(n, m) } case class Complex(re: Double, im: Double) { override def toString: String = re + " + " + im + "i" } class ComplexMonoid extends Monoid[Complex] { val identity = Complex(0, 0) def op(z: Complex, w: Complex): Complex = { Complex(z.re + w.re, z.im + w.im) } } implicit val complexMonoid = new ComplexMonoid 

Using the above, I can now do Complex(1, 2) + Complex(3, 1) , giving Complex = 4.0 + 3.0i . This is great for reusing code, since now I can add additional functions for the Monoid and withAdd functions (for example, resorting to an element from time to time, providing a power function for multiplication), and this will work for any case class that has the corresponding monoid, Only with complex numbers and trying to include doubles, ints, etc., I then ran into the problem above.

+6
source share
1 answer

I would use a regular class , not a case class . Then it would be easy to create methods to add or subtract these complex numbers, for example:

 class Complex(val real : Double, val imag : Double) { def +(that: Complex) = new Complex(this.real + that.real, this.imag + that.imag) def -(that: Complex) = new Complex(this.real - that.real, this.imag - that.imag) override def toString = real + " + " + imag + "i" } 

As the original page shows, it now supports what looks like operator overloading (this is not the case because + and - are functions, not operators).

The problem with the implicit class NumberWithAdd and its + method is that the same method exists in number classes such as Int and Double . The + NumberWithAdd method basically lets you start with a number that can be sent to Complex and add a Complex object to this first element. That is, the left value can be anything (as long as it can be converted), and the right value must be Complex .

This works fine for w + z (no need to convert w ) and 1 + z (implicit conversion for Int to Complex ). It does not work for z + 1 because + not available in the Complex class. Since z + 1 is actually z.+(1) , Scala will look for other possible matches for +(i: Int) in the classes into which Complex can be converted. It also checks for NumberWithAdd , which has a + function, but this requires Complex as the right value. (It will correspond to a function that requires Int as the right value.) There are other functions called + that accept Int , but there is no conversion from Complex to what these functions want as left-hand values.

The same definition + works when it is in the (case) Complex class. In this case, both w + z and z + 1 simply use this definition. The 1 + z case is now a little more complicated. Since Int does not have a + function that takes the value Complex , Scala will find the one that does (in Complex ) and determine whether it is possible to convert Int to Complex . This is possible using implicit functions; the function is being transformed and executed.

When the + function in the NumberWithAdd class NumberWithAdd renamed add , there is no confusion with the functions in Int , because Int does not have a + function. Thus, Scala will try to apply the add function and will perform the conversion to Int to Complex . He will even do this conversion when trying 1 add 2 .

Note. My explanations may not fully describe the actual inner workings.

0
source

All Articles