Now that Kim Stebel helped me understanding how to type variables with existential types, i need to know how to use them in inheritance:
the following code doesn’t compile:
class PagingListModel(startPageNumber: Int, pageSize: Int, query: Query[Projection[_ <: Product]]) extends AbstractListModel {
val itemStartNumber: Int = startPageNumber * pageSize
val items: List[Product] = getPageData()
override def getPageData(): List[Product] = {
db withSession {
return queryToQueryInvoker(query.drop(itemStartNumber).take(pageSize)).list
}
}
}
…with the error:
no type parameters for method queryToQueryInvoker:
(q: org.scalaquery.ql.Query[org.scalaquery.ql.ColumnBase[T]])
org.scalaquery.ql.basic.BasicQueryInvoker[T]
exist so that it can be applied to arguments
(org.scalaquery.ql.Query[org.scalaquery.ql.Projection[_ <: Product]])
--- because ---
argument expression's type is not compatible with formal parameter type;
found : org.scalaquery.ql.Query[org.scalaquery.ql.Projection[_ <: Product]]
required: org.scalaquery.ql.Query[org.scalaquery.ql.ColumnBase[?T]]
…which is strange, because the required type is really inside the bounds of the found one…
PS: i really only want to be able to call foreach
on each Tuple in the list returned by getPageData()
…
I don't think this can be done with an existential type. It works with a type parameter:
The original version would be correct but Scala cannot typecheck it due to a limitation similar to Haskell's monomorphism restriction. The type parameter for queryToQueryInvoker would have to be a universal type
[T <: Product] forAll { type T }
which is not supported by Scala.By using an explicit type parameter, queryToQueryInvoker can be instantiated with that specific type. The method can still return
List[_ <: Product]
because List is co-variant in its element type.Edit: It is possible after all. You have to move the existential to the right place:
Without the extra variable
i
the compiler will infer the wrong type and then complain about it. Looks like a bug to me.My knowledge of ScalaQuery is limited, but it looks as though you should be parameterizing the class.
Existentials can be tricky, and are best avoided if at all possible.