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.
You can't have an abstract method in a concrete class. If you want an abstract method, the class must also be abstract. Otherwise users could instantiate the class and try to implement its methods. However, if your class is abstract, it may have some methods that are abstract and others that are concrete.
A concrete class is a class that has an implementation for all of its methods. They cannot have any unimplemented methods. It can also extend an abstract class or implement an interface as long as it implements all their methods.
I understand this sounds asymmetrical but the answer is no. An abstract class cannot be instantiated and therefore cannot be used as a member of another class.
An abstract class can have a data member, abstract method, method body (non-abstract method), constructor, and even main() method.
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
^
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With