Covariance and type inference in Scala -


given code

object renderer {    sealed abstract class basicrender    case class renderimages(img: array[file]) extends basicrender    case class rendervideo(video: file) extends basicrender    def rendererfor[t <: basicrender : manifest, z <: render.renderingcontext](ctx: z): option[render[t]] = {     val z = manifest[t].erasure     if (z == classof[renderimages]) {       some(new imagesrenderer(ctx.asinstanceof[imagescontext])) // .asinstanceof[render[t]])     } else     if (z == classof[rendervideo]) {       some(new videorenderer(ctx.asinstanceof[videocontext])) // .asinstanceof[render[t]])     } else {       none     }   }    private class imagesrenderer(ctx: imagescontext) extends render[renderimages] {      override def renderjson(json: string)(implicit jsctx: phantomjscontext) = {       none     }    }    private class videorenderer(ctx: videocontext) extends render[rendervideo] {      override def renderjson(json: string)(implicit jsctx: phantomjscontext) = {       none     }    }   }  trait render[+out] {    def renderjson(json: string)(implicit jsctx: phantomjscontext): option[out]  } 

i made render trait covariant it's type parameter, if

renderimages <: basicrender  

then

imagesrenderer <: render[renderimages] 

but looks compiler not able infer type of renderer in rendererfor, need add explicit class casting like

some(new imagesrenderer(ctx.asinstanceof[imagescontext]).asinstanceof[render[t]]) 

what wrong reasoning here?

as explained daniel c. sobral, problem here instantiating different renderers dynamically, in way not capture in type system relation between ctx , result type of rendererfor. 1 common way solve kind of issues use type class:

import java.io.file  class phantomjscontext  trait renderer[+out] {   def renderjson(json: string)(implicit jsctx: phantomjscontext): option[out] }  trait rendererfactory[contexttype, resulttype] {   def buildrenderer( ctx: contexttype ): renderer[resulttype] }  object renderer {   case class renderimages(img: array[file])   case class rendervideo(video: file)    trait imagescontext     trait videocontext    def rendererfor[contexttype, resulttype](ctx: contexttype)( implicit factory: rendererfactory[contexttype, resulttype] ): renderer[resulttype] = {     factory.buildrenderer( ctx )   }    class imagesrenderer(ctx: imagescontext) extends renderer[renderimages] {     def renderjson(json: string)(implicit jsctx: phantomjscontext) = ???   }   implicit object imagesrendererfactory extends rendererfactory[imagescontext, renderimages] {     def buildrenderer( ctx: imagescontext ) = new imagesrenderer( ctx )   }    class videorenderer(ctx: videocontext) extends renderer[rendervideo] {     def renderjson(json: string)(implicit jsctx: phantomjscontext) = ???   }   implicit object videorendererfactory extends rendererfactory[videocontext, rendervideo] {     def buildrenderer( ctx: videocontext ) = new videorenderer( ctx )   } } 

you can check in repl correct types returned:

scala> lazy val r1 = renderer.rendererfor( new renderer.imagescontext {} ) r1: renderer[renderer.renderimages] = <lazy>  scala> :type r1 renderer[renderer.renderimages]  scala> lazy val r2 = renderer.rendererfor( new renderer.videocontext {} ) r2: renderer[renderer.rendervideo] = <lazy>  scala> :type r2 renderer[renderer.rendervideo] 

Comments

Popular posts from this blog

SPSS keyboard combination alters encoding -

Add new record to the table by click on the button in Microsoft Access -

javascript - jQuery .height() return 0 when visible but non-0 when hidden -