6

Given the following traits and class. Why does this compile? Can this be actually used for something?

trait Container {
  type A
}

trait AnotherContainer[B]{
    def x(b : B) : B
}

trait Mixed extends Container with AnotherContainer[Container#A]

class Impl extends Mixed{
    def x(a : Container#A) = a 
}

new Impl().x _

scala> new Impl().x _
res0: (Container#A) => Container#A = <function>

Update:

class Baz { type T; }

Is actually a feature but I could not find the motivation for it: #1753.

Thomas Jung
  • 32,428
  • 9
  • 84
  • 114
  • Why? B in the instance of AnotherContainer in Mixed is A, so the signature for x is consistent between AnotherContainer.x and Impl.x. Or am I missing something? – Randall Schulz Jan 22 '10 at 17:14
  • @Randall Well, `type A` is abstract, and I don't see it becoming concrete anywhere. So I'd expect `Impl` not to compile, returning a "needs to be abstract" error. – Daniel C. Sobral Jan 22 '10 at 23:49
  • It's intentional that this is allowed; see https://issues.scala-lang.org/browse/SI-1753 for more information. – Seth Tisue Sep 23 '15 at 18:39

2 Answers2

3

In your example, the compiler adds the default type bounds of >: Nothing <: Any. The second example below shows a case where an abstract type becomes usable (if not useful).

scala> trait T { type A >: Nothing <: Any }
defined trait T

scala> 1: T#A
<console>:6: error: type mismatch;
 found   : Int(1)
 required: T#A
       1: T#A
       ^

scala> trait T { type A >: Int <: Int }
defined trait T

scala> 1: T#A                          
res6: T#A = 1

scala> "": T#A
<console>:6: error: type mismatch;
 found   : java.lang.String("")
 required: T#A
       "": T#A
       ^
retronym
  • 54,768
  • 12
  • 155
  • 168
  • 1
    `trait T { type A >: Int <: Int }` is just a complicated way to define `trait T { type A = Int }` the result is the the same. – Thomas Jung Feb 03 '10 at 14:39
2

It looks harmless if useless to me. The type that x wants doesn't exist, so you can't pass it to the method. Whether harmless uselessness should be a compile-time error is a matter of taste, I suppose.

If you look at what x actually does, it decompiles thusly:

public java.lang.Object x(java.lang.Object);
  Code:
   0:   aload_1
   1:   areturn

which is exactly what the identity method should do (load the argument regardless of type, return it). You can write something equivalent with much less code:

trait AbstractType { type T }
class Useless extends AbstractType { def identity(t: AbstractType#T) = t }

Except nothing has type AbstractType#T, so again we have uselessness.

Unless I'm missing something.

Rex Kerr
  • 166,841
  • 26
  • 322
  • 407