The problem is that a ColumnInfo[User]
is not a ColumnInfo[Bean]
. For example, if you have
val myInfo = ColumnInfo[User]("MyCol", user => user.name)
val myBean = new Bean
myInfo.value(myBean)
There's no way this can possibly work, since myBean
has no name
method (even if we could force it to compile, it would fail at run-time), so the compiler catches this and throws it out.
In fact, ColumnInfo
appears to be contravariant in T
(anything that goes into a function is contravariant, for the reasons demonstrated in the example - in some languages, they actually use the keyword in
for contravariance, to make this clear).
You could therefore define ColumnInfo
like:
case class ColumnInfo[-T](name: String, value: T => Any)
Unfortunately, this limits re-use of your template, as its signature has to be @(list: List[User], columns: List[ColumnInfo[User]])
In an ideal world, templates would support type parameters, like regular Scala methods, so you could have a signature like @[T](list: List[T], columns: List[ColumnInfo[T]])
. However, Play templates do not currently support type parameters.
I can see two ways around this
Existential Types
We can hack around it with existential types. We'll wrap up our arguments to the template into an invariant case class:
case class TableData[T](list: List[T], columns: List[ColumnInfo[T]])
and change the signature of the template to:
@(cols: TableData[T forSome {type T}])
We now have to change list
to cols.list
and columns
to cols.columns
in our template to match up.
We can call our template like:
// In ListController...
Ok(views.html.list(TableData(users, columns)))
Casts
Alternatively, we can cast around the problem. Give your template a signature of:
@(list: List[Any], columns: List[ColumnInfo[Any]])
and cast columns
to List[ColumnInfo[Any]]
when you actually call it:
// In ListController...
Ok(views.html.list(users, columns.asInstanceOf[List[ColumnInfo[Any]]]))
This will compile, as Scala uses type erasure. And provided list
is actually a List[User]
, the types will be correct at run-time.