How to define a function that works with unrelated types in Scala?

I would like to define a function that applies * 2 to its argument, which works for all types where it makes sense. I tried using structural types:

 import scala.language.reflectiveCalls def double[T](x: Any{def * (arg0: Int): T}) = x * 2 

It works for strings:

 scala> double("a") res85: String = aa 

But not for numbers:

 scala> double(4) java.lang.NoSuchMethodException: java.lang.Integer.$times(int) at java.lang.Class.getMethod(Class.java:1778) at .reflMethod$Method1(<console>:18) at .double(<console>:18) ... 32 elided 
  • Why do I need this error message?
  • Is it possible to do what I want using structural types?
  • Can this be done in another way?

Change By "do what I want", I mean working with already existing types, such as numbers and strings, and not just for classes that I define myself.

+8
types scala
source share
3 answers
  • * translates to $times , the structural type checks for the existence of the method * , but (I believe the error) calls it internal ( $times ) representations). This works for String , because there are $times for them.

  • This approach should work for methods with names that contain only letters.

`` ``

 import scala.language.reflectiveCalls def double[T](x: Any{def test (arg0: Int): T}) = x.test(2) class A { def test(i: Int) = i * 10 } class B { def test(i: Int) = i * 20 } scala> double(new A) res0: Int = 20 scala> double(new B) res1: Int = 40 
  1. Yes, the idiomatic answer is styles. You choose what "significance" is. And they can be applied to any existing class:

`` ``

 trait Multiply[A]{ def times(a: A, x: Int): A } implicit val MultString = new Multiply[String] { def times(a: String, x: Int) = a * x } implicit val MultInt = new Multiply[Int] { def times(a: Int, x: Int) = a * x } def double[T](t: T)(implicit mult: Multiply[T]) = mult.times(t, 2) scala> double("aaaa") res0: String = aaaaaaaa scala> double(111) res1: Int = 222 

Also note that structural typing uses reflection => rather slowly.

+3
source share

You can always just overload the method. For it to work in REPL, you must :paste use it as a block.

 def double(s:String):String = s * 2 def double[N](n:N)(implicit ev: Numeric[N]):N = { import Numeric.Implicits._ n * ev.fromInt(2) } double("this") // result: String = thisthis double(3L) // result: Long = 6 
+3
source share

Another opportunity I found is to use macros. As of Scala 2.11.8, they are still experimental, and according to Martin Odersky will not be saved in this form. The current syntax is awkward, but so far this is the only method that is completely DRY ( * 2 written only once, and the function works on all types that support this operation).

Regardless of whether this is the best solution, I post it for completeness:

 import reflect.macros.Context def doubleImpl[T](c: Context)(x: c.Expr[T]): c.Expr[T] = { import c.universe._ c.Expr(q"${x.tree} * 2") } def double[T](x: T): T = macro doubleImpl[T] 
0
source share

All Articles