Question

I thinks it's easier to explain it with a simple example. (help rephrasing the title is welcome ;-)

I'd like to implement a squared method and, using implicit def, automatically add it to any class that supports the *-operator.

With an Int it's very easy:

class EnhancedInt(x: Int) { def squared = x * x }

implicit def IntToEnchancedInt(x: Int) = new EnhancedInt(x)

But with Any or AnyVal I get the following error:

scala> class EnhanceAny(x: AnyVal) { def squared = x * x }
<console>:7: error: value * is not a member of AnyVal
       class EnhanceAny(x: AnyVal) { def squared = x * x }

I'd like to know how I could apply it to any numeric class, or, even better, to any class supporting the *-operator.

Was it helpful?

Solution

It's not possible to have solution that works on any type with a * method without writing a boilerplate conversion for each type you want to deal with. Essentially to do that you would need a recursive structural type, and Scala does not support those because of JVM type erasure. See this post for more details.

You can get fairly close to what you want using a type class along with the Numeric type class, (inspired by the answers to this and this question). This will work with most primitives:

//define the type class
trait Multipliable[X] { def *(x: X): X}

//define an implicit from A <% Numeric[A] -> Multipliable[Numeric[A]]
implicit def Numeric2Mult[A](a: A)(implicit num: Numeric[A]): Multipliable[A] = new Multipliable[A]{def *(b: A) = num.times(a, b)}

//now define your Enhanced class using the type class
class EnhancedMultipliable[T <% Multipliable[T]](x: T){ def squared = x * x}

//lastly define the conversion to the enhanced class
implicit def Mult2EnhancedMult[T <% Multipliable[T]](x: T) = new EnhancedMultipliable[T](x)

3.squared
//Int = 9

3.1415F.squared
//Float = 9.869022

123456789L.squared
//Long = 15241578750190521

OTHER TIPS

Think about it. Multiplication have different properties on different objects. Integer multiplication, for example, is associative and commutative, scalar multiplication is not commutative. And multiplication on floating point numbers... But, of course, you can have what you want with trait or with "trait and implicit" construction which resembles a typeclass.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top