简体   繁体   中英

Can I use a type bound on a Scala abstract method and then “tighten up” the definition in a subclass?

Essentially I want to do something like this:

class Shape

class CoordSystem
class C3D(val x: Double, y: Double, z: Double) extends CoordSystem
class C2D(val x: Double, y: Double) extends CoordSystem

abstract class Shape {
  def getCoords[C <: CoordSystem]: List[C]
} 

class Pyramid extends Shape {
  def getCoords: List[C3D] = 
    List(new C3D(1,2,1), new C3D(1,1,1), new C3D(2,2,1), new C3D(2,1,1), new C3D(1.5,1.5,3))
}   
>> error: class Pyramid needs to be abstract, since method getCoords in class Shape of type [C <: CoordSystem]List[C] is not defined

I've seen a handful of different ideas on this answer , but none of them seem quite right for this case - because they don't seem to let me write code elsewhere which refers to myShape.getCoords as if it's been correctly defined in a Shape subclass, returning a List of objects from a subclass of CoordSystem .

I also found an interesting discussion about generics on the Scala Lang email list, but couldn't quite tie it back to my situation.

Any help gratefully appreciated!

How about something like this:

class CoordSystem
class C3D(val x: Double, y: Double, z: Double) extends CoordSystem
class C2D(val x: Double, y: Double) extends CoordSystem

trait ShapeLike[+C <: CoordSystem] {
  def getCoords: List[C]
}

abstract class Shape extends ShapeLike[CoordSystem]

class Pyramid extends Shape with ShapeLike[C3D] {
  def getCoords: List[C3D] =
    List(new C3D(1, 2, 1), new C3D(1, 1, 1), new C3D(2, 2, 1), new C3D(2, 1, 1), new C3D(1.5, 1.5, 3))
}

Of course, nothing forces you to declare the extra type ShapeLike to do this; its purpose is to allow you to use the type Shape without annoying extra type parameters.

So, actually the answer to your question as stated in the title is: you may “tighten up” the type bound of a type parameter in a subclass if it is defined as a covariant type parameter in the superclass; conversely, you may “loosen” the type bound of a contravariant type parameter.

A type parameter is a type parameter, and the super class contract demands that you do not tighten its contract -- making it less strict would not violate the contract, though I don't think it is allowed.

You can do something else, however: put the type inside the class.

class Shape

class CoordSystem
class C3D(val x: Double, y: Double, z: Double) extends CoordSystem
class C2D(val x: Double, y: Double) extends CoordSystem

abstract class Shape {
  type C <: CoordSystem
  def getCoords: List[C]
} 

class Pyramid extends Shape {
  override type C = C3D
  def getCoords: List[C3D] = 
    List(new C3D(1,2,1), new C3D(1,1,1), new C3D(2,2,1), new C3D(2,1,1), new C3D(1.5,1.5,3))
}   

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM