Michael Zajac
Michael Zajac

Reputation: 55569

Scala abstract class/trait with methods that return the sub-type

Lately I've found myself working with different objects with similar structures (using play framework, but that's not really important) that I would like to store as different classes. They'll often have CRUD methods that are fundamentally the same, so I would like each of these classes to inherit from an abstract type to cut down on code duplication. The problems I'm running into are: 1.) Being able to return the sub-type, and 2.) Accessing fields of the sub-type within these abstract methods.

I was successfully able to get this working (in a more fleshed-out version) with get methods taking advantage of apply, but now I've hit a wall. This is a highly simplified version to express my problem, so the implementation of create has been cut down. (The actual create method needs to access the object's fields, sending them to a database, etc..)

abstract class FileSystemObject(id: Int, path: String)

trait FileSystem[T <: FileSystemObject] {
    val table: String

    def apply(id: Int, path: String): T

    def create(obj: T): Option[T] = Some(apply(1, obj.path))

}

case class File(id: Int, path: String) extends FileSystemObject(id, path)

object File extends FileSystem[File] {
    val table: String = "files"
}

.. Which results in error: value path is not a member of type parameter T

At this point, it seems the solution I've chosen is horribly flawed, but I don't know how to proceed from here.

Upvotes: 1

Views: 340

Answers (1)

dhg
dhg

Reputation: 52681

You need path to be accessible on FileSystemObject in order for it to be seen on T. Try making it a def that gets overridden by the concrete class:

abstract class FileSystemObject {
  def id: Int
  def path: String
}

case class File(id: Int, path: String) extends FileSystemObject

Upvotes: 4

Related Questions