Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala trait function: return instance of derived type

Tags:

scala

traits

I have a trait Book that looks like this

trait Book{
 val sqlTableName;
 def getAll: Seq[ Book ] = { magicSQLFn( $"SELECT * FROM $sqlTableName" ) }
}

I have two derived types:

class Fiction extends Book{ val sqlTableName = "fiction" }
class NonFiction extends Book{ val sqlTableName = "nonfiction" );

I need to get Seq[Fiction] when I call getAll on an instance of Fiction, say fiction1. I know one way to do would be to do a .map( _.asInstanceOf[ Fiction ] ). However, is there a way to avoid this altogether?

Actually, I realize the less wrong way to do would be to be able to define a companion object for Fiction that extends Book so that I can call getAll on that object (as opposed to doing it on an instance), however, in that case, I'm not sure how I'll convert the individual elements in the returned sequence to instances of Fiction class because Fiction class will no longer derive from Book. Should I have two differently named Book traits? One that is the super of these objects, and the other that is the super class of these classes?

EDIT: @Travis Brown's reply solves my initial problem. If anyone have comments on how to handle this using companion objects and not class instances, that'd be great too!

like image 426
0fnt Avatar asked Oct 29 '14 12:10

0fnt


1 Answers

This is more or less the classic use case for F-bounded polymorphism, which allows you to refer to the specific subtype in methods on the supertype:

trait Book[B <: Book[B]] {
  val sqlTableName;
  def getAll: Seq[B] = { magicSQLFn( $"SELECT * FROM $sqlTableName" ) }
}

class Fiction extends Book[Fiction] { val sqlTableName = "fiction" }
class NonFiction extends Book[NonFiction] { val sqlTableName = "nonfiction" )

(This assumes that your magicSQLFn will return something with the appropriate static type, but it is magic, after all.)

F-bounded polymorphism has its detractors, and there are issues to watch out for, but it's a fairly widely used pattern in both Scala and Java.

like image 168
Travis Brown Avatar answered Dec 08 '22 08:12

Travis Brown