Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Concrete classes with abstract type members

Tags:

types

scala

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.

like image 603
Thomas Jung Avatar asked Jan 22 '10 07:01

Thomas Jung


People also ask

Can concrete classes contain abstract methods?

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.

Do concrete classes have member methods?

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.

Can an abstract class have members?

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.

What members are in abstract class?

An abstract class can have a data member, abstract method, method body (non-abstract method), constructor, and even main() method.


2 Answers

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
       ^
like image 96
retronym Avatar answered Sep 19 '22 06:09

retronym


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.

like image 23
Rex Kerr Avatar answered Sep 20 '22 06:09

Rex Kerr