Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generics in Scala: implementing an interface/trait twice?

Given a generic interface such as the following

interface I<T> {
    void m(T t);
}

I can in C# create a class that implements I twice (or more) with different types supplied for T, e.g.

class C : I<int>, I<String> {
   public void m(int i) { }
   public void m(String s) { }
}

This cannot be done in Java due to erasure of the generic type info, but can something like this be achieved in Scala?

like image 645
Eyvind Avatar asked Sep 27 '11 07:09

Eyvind


2 Answers

No. Mixing in the same trait is only possible in Scala if the 2 types with which the trait (interface) is parametrized with types that conform to each other and the trait is not mixed into the same class twice directly. To ensure that the 2 types conform to each other, you will generally have to make the type parameter covariant (+).

For example, this is not allowed:

scala> trait A[+T] { def foo: T = sys.error() }
defined trait A

scala> class C extends A[AnyRef] with A[String]
<console>:8: error: trait A is inherited twice
       class C extends A[AnyRef] with A[String]

But this is:

scala> trait A[+T] { def foo: T = sys.error() }
defined trait A

scala> class C extends A[AnyRef]
defined class C

scala> class B extends C with A[String]
defined class B

Note that in this case you will not obtain the overloading semantics as is the case with C#, but the overriding semantics - all the methods in A with the conforming signature will be fused in one method with the most specific signature, choosing the method according to linearization rules, rather than having one method for each time you've mixed the trait in.

like image 92
axel22 Avatar answered Sep 20 '22 11:09

axel22


No, it can't. Generally what I do in this case is

class C {
  object IInt extends I[Int] { ... }
  object IString extends I[String] { ... }
  ...
}
like image 41
Alexey Romanov Avatar answered Sep 19 '22 11:09

Alexey Romanov