1

I am quite new to Scala programming. Besides Scala, I have never learned functional programming. With that said, I am currently trying to figure out a good way to define traits, classes, etc, on a project using slick.

My idea was to have a trait having the methods to be implemented on the child classes, and some would be implemented on the parent class itself. I found a way that works but I have no idea why. Not sure if this problem is related to how Slick or Scala works.

I was using a construction like:

trait CompanyDAO extends BaseDao[Company]{
 self: DBProfile  =>

But this give the following type mismatch error:

[error] found : slick.lifted.TableQuery[CompanyDAO.this.CompanyTable] [error] required: slick.lifted.TableQuery[CompanyDAO.this.profile.api.Table[Company]] [error] (which expands to) slick.lifted.TableQuery[CompanyDAO.this.profile.Table[Company]] [error] Note: CompanyDAO.this.CompanyTable <: CompanyDAO.this.profile.api.Table[Company], but class TableQuery is invariant in type E. [error] You may wish to define E as +E instead. (SLS 4.5) [error] override def toTable = TableQuery[CompanyTable]

But, if I use

self: DBProfile with BaseDao[Company] =>

Then the compilation works (BTW, got the solution from another post)

So, my questions:

1) Why using self-types toTable assignment works while extending the trait do not? How scala interprets the type of toTable in both scenarios?

2) Is there a way to adapt the "trait CompanyDAO extends BaseDao" to solve the error?

Thank you in advance.

import scala.concurrent.Future
import slick.basic.DatabaseConfig
import slick.jdbc.JdbcProfile

trait DBConfiguration {
  lazy val config = DatabaseConfig.forConfig[JdbcProfile]("mytrade")
}

trait DBProfile {
  val config: DatabaseConfig[JdbcProfile]
  val db: JdbcProfile#Backend#Database = config.db
  val profile : JdbcProfile = config.profile
}

trait BaseDao[T <: Any] {
  self: DBProfile =>

  import profile.api._
  import slick.lifted.TableQuery

  def toTable():TableQuery[Table[T]]
  def findAll():Future[Seq[T]] = db.run(toTable.result)
}

case class Company(name: String, code: Int)

// If I use the construction like the comment below, it will fail
//trait CompanyDAO extends BaseDao[Company]{
    //self: DBProfile  =>

trait CompanyDAO {
  self: DBProfile with BaseDao[Company] =>
  //import from DBProfile trait
  import profile.api._

  class CompanyTable(tag: Tag) extends Table[Company](tag, "COMPANY") {

    import slick.ast.BaseTypedType
    import slick.jdbc.JdbcType

    def name = column[String]("name")
    def code = column[Int]("code")

    def * = (name, code) <> (Company.tupled, Company.unapply)
  }

  override def toTable = TableQuery[CompanyTable]
}

EDIT: some other things I have been trying

Extending BaseDao, If I change the declaration of toTable to:

def toTable[S <: TableQuery[Table[_]]]():S

The type mismatch goes away but I receive now:

test.scala:27: dead code following this construct [error] def findAll():Future[Seq[T]] = db.run(toTable.result)

Tried also using self-type and it gave me the same error.

1

1 Answer 1

0

If I change the declaration of toTable to:

def toTable[S <: TableQuery[Table[_]]]():S

The type mismatch goes away but I receive now:

test.scala:27: dead code following this construct [error] def findAll():Future[Seq[T]] = db.run(toTable.result)

Any ideas why is this happening?

I can't reproduce your specific compile error.

But when I change the line

def toTable():TableQuery[Table[T]]

to

def toTable[S <: TableQuery[Table[_]]]():S

I have compile error

Error:(24, 51) value result is not a member of Nothing
    def findAll():Future[Seq[T]] = db.run(toTable.result)

This is because type parameter S is inferred to be Nothing.

You don't provide implementation for the method toTable and Nothing <: TableQuery[Table[_]].

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for the references, really helpful. Just for reference, I am using Scala 2.12.1 with Slick 3.2.0. What I cannot understand is why toTable(): TableQuery[Table[T]] works with self-types and do not work if I use inheritance. How scala interprets the type of this variable in each case, what is the logic?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.