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.
The declaration of a generic class is almost the same as that of a non-generic class except the class name is followed by a type parameter section. The type parameter section of a generic class can have one or more type parameters separated by commas.
A generic class and a generic method can handle any type of data.
The classes that takes a type just like a parameter are known to be Generic Classes in Scala. This classes takes a type like a parameter inside the square brackets i.e, [ ].
To use a generic class, put the type in the square brackets in place of A . The instance stack can only take Ints. However, if the type argument had subtypes, those could be passed in: Scala 2.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With