Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why columns in slick Tables are defs instead of vals?

Tags:

scala

slick

In slick documentation columns in table are defined with def

class Coffees(tag: Tag) extends Table[(String, Int, Double, Int, Int)](tag, "COFFEES") {
  def name = column[String]("COF_NAME", O.PrimaryKey)
  def supID = column[Int]("SUP_ID")
  def price = column[Double]("PRICE")
  def sales = column[Int]("SALES", O.Default(0))
  def total = column[Int]("TOTAL", O.Default(0))
  def * = (name, supID, price, sales, total)
}

Is there a reason why it shouldn't be like this:

class Coffees(tag: Tag) extends Table[(String, Int, Double, Int, Int)](tag, "COFFEES") {
  val name = column[String]("COF_NAME", O.PrimaryKey)
  val supID = column[Int]("SUP_ID")
  val price = column[Double]("PRICE")
  val sales = column[Int]("SALES", O.Default(0))
  val total = column[Int]("TOTAL", O.Default(0))
  val * = (name, supID, price, sales, total)
}

It seems like columns don't use anything that could change.

like image 565
Łukasz Avatar asked Jan 29 '26 23:01

Łukasz


1 Answers

Short answer: initialization order.

Long answer:

Lets gather some facts:

1) using vals instead of defs mostly works (if you change most of defs to vals in your code it would most of the time behave correctly - at least this is how it works for me)

2) most examples of Slick code use defs.

So it may be that if something wrong happens it happens only in some (rare?) cases.

Some light may be shed by this part of code in Slick itself (take a look at comment after if(tt == null) (class `RelationalProfile):

def column[C](n: String, options: ColumnOption[C]*)(implicit tt: TypedType[C]): Rep[C] = {
      if(tt == null) throw new NullPointerException(
        "implicit TypedType[C] for column[C] is null. "+
        "This may be an initialization order problem. "+
        "When using a MappedColumnType, you may want to change it from a val to a lazy val or def.")
      new Rep.TypedRep[C] {
        override def toNode =
          Select((tableTag match {
            case r: RefTag => r.path
            case _ => tableNode
          }), FieldSymbol(n)(options, tt)) :@ tt
        override def toString = (tableTag match {
          case r: RefTag => "(" + _tableName + " " + r.path + ")"
          case _ => _tableName
        }) + "." + n
      }
    }

If you take a look at commit that introduced this change: https://github.com/slick/slick/commit/be2ff6513d46abc9a25c8752c2931a786d4c5ad6

you should find pretty good explanation (commit comments).

like image 200
Paul Dolega Avatar answered Jan 31 '26 15:01

Paul Dolega



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!