12

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?

Eyvind
  • 5,221
  • 5
  • 40
  • 59
  • Can you describe in Scala code what you want to do. Many people here are not familiar with C#. – Jus12 Sep 27 '11 at 08:31
  • Well, I'm not all that familiar with Scala (trying to learn :)). However, the code above should be easy to understand for anyone who knows Java, as long as you know that the ":" after "class C" in this setting means "implements" in Java-speak. What I have tried in Scala is to make I into a trait (just replace "interface" with "trait"), and then define C as "class C extends I with I { ... ", but that does not work. – Eyvind Sep 27 '11 at 08:39
  • In Scala Generic types are enclosed in `[]` so you would do this as `I[Int]` and `I[String]`. Have you tried using `ClassManifest` in the declaration? – Jus12 Sep 27 '11 at 08:43
  • Ahh, I know, the <...> were just a typo. What would I use the ClassManifest for? – Eyvind Sep 27 '11 at 08:49
  • Note that Scala compiles to ordinary Java bytecode, so if this "cannot be done in Java due to erasure of the generic type info", then the same applies to Scala (although to be fair Scala does get around some of the JVM's limitations with compiler cleverness). – Ben Sep 27 '11 at 11:42

2 Answers2

13

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.

axel22
  • 32,045
  • 9
  • 125
  • 137
11

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

class C {
  object IInt extends I[Int] { ... }
  object IString extends I[String] { ... }
  ...
}
Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487