Why does Scala type inference fail in one case but not the other? -
background: i'm using net.liftweb.record
mongodb access database. @ point, in need of drawing table of collection of documents database (and render them ascii table). ran obscure type inference issues easy solve nevertheless made me want understand why happening.
reproduction: simplicity, i've reduced code (what think is) absolute minimum, depends on net.liftweb.record
, none of mongo specific types. i've kept real-life body of function under question make example more realistic.
maketable
takes apples, , functions map apples columns. columns can either mapped real field on apples, or dynamically computed value (with name). able mix 2 (real fields , dynamic values) in single seq
, defined structural type col
.
to see how code (below) behaves, try following variants of cols
parameter maketable
:
// ok: cols = seq(_.isdone) cols = seq(job => dyncol1) cols = seq(job => dyncol1, job => dyncol2) // error: found: seq[job => object], required: seq[job => test.col] cols = seq(_.isdone, job => dyncol1) cols = seq(_.isdone, job => dyncol2) cols = seq(_.isdone, job => dyncol1, job => dyncol2)
...so whenever _.isdone
(i.e. column maps physical field) mixed other "flavor" of column, error occurs (case 1). alone behaves well; other flavors of column behave when alone or mixed (case 2).
intuitive workaround: marking cols
seq[job => col]
fixes error.
counter-intuitive workaround: explicitly marking any of return values of functions in seq
col
, or of functions job => col
, solves issue.
the code:
import net.liftweb.record.{ record, metarecord } import net.liftweb.record.field.intfield import scala.language.reflectivecalls class job extends record[job] { def meta = job object isdone extends intfield(this) } object job extends job metarecord[job] object test extends app { type col = { def name: string; def get: } def maketable[t](xs: seq[t])(cols: seq[t => col]) = { assert(xs.size >= 1) val rows = xs map { x => cols { map { _(x).get } } val header = cols map { _(xs.head).name } (header +: rows) } val dyncol1 = new { def name = "dyncol1"; def = "dyn1" } val dyncol2 = new { def name = "dyncol2"; def = "dyn2" } val jobs = seq(job.createrecord, job.createrecord) maketable(jobs)(seq( _.isdone, job => dyncol1, job => dyncol2 )) }
p.s. i'm not adding lift or lift-record tag because think not related lift , scala question triggered happens lift-specific situation. feel free correct me if i'm wrong.
Comments
Post a Comment