Greg
Greg

Reputation: 11512

How can I have a typed (specific) factory in a base trait in Scala?

Here's the behavior I'm trying to achieve:

trait PathLike {
  val given: String

  def factory[T <: PathLike]( g: String ):T

  def +[T <: PathLike]( part: String ): T = factory(this.given+"/"+part)
}

case class Path( given: String ) extends PathLike {
  def factory[Path]( g: String ) = Path(g)
}
case class NonRelativePath( given: String ) extends PathLike {
  def factory[NonRelativePath]( g: String ) = NonRelativePath(g)
}

I have other functions in PathLike that use + so simply moving the + function into each of the specific case classes doesn't seem like a good option.

Currently the compiler complains:

type mismatch;  found   : com.foo.Path  required: Path  Path.scala
type mismatch;  found   : com.foo.NonRelativePath  required: NonRelativePath    Path.scala

Why is it complaining as it has Path/NonRelativePath respectively? How can I construct a properly typed child of PathLike from within PathLike?

Upvotes: 1

Views: 73

Answers (2)

senia
senia

Reputation: 38045

You should use a trait type parameter instead of method type parameter since it should be applied on instance creation instead of method application.

trait PathLike[T <: PathLike] {
  val given: String

  def factory( g: String ):T

  def +( part: String ): T = factory(this.given+"/"+part)
}

case class Path( given: String ) extends PathLike[Path] {
  def factory( g: String ) = Path(g)
}
case class NonRelativePath( given: String ) extends PathLike[NonRelativePath] {
  def factory( g: String ) = NonRelativePath(g)
}

Using def factory[Path]( g: String ) = you are creating a new name for methods type parameter. See these answers for additional information about type shadowing: 1, 2, 3.

Upvotes: 2

Sumeet Sharma
Sumeet Sharma

Reputation: 2583

Explicitly add the return type in the definition.

def factory[Path]( g: String ): Path = Path(g)

Upvotes: 0

Related Questions