Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala: Is it possible to indicate a generic class which implements a certain method

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.

like image 722
opensas Avatar asked Jan 14 '12 22:01

opensas


People also ask

How do you specify a generic class?

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.

Can generic class handle any type of data?

A generic class and a generic method can handle any type of data.

Does Scala support generics?

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, [ ].

How do I use generic in Scala?

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.


1 Answers

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
like image 110
Dan Simon Avatar answered Oct 19 '22 05:10

Dan Simon