Scala: Enforcing A is not a subtype of B -


i trying overload method based on whether or not parameter extends given class, , have been having trouble. using an approach miles sabin, produced following code:

object extendedgenerictypes {    trait <:!<[a, b] // encoding "a not subtype of b"    // use ambiguity rule out cases we're trying exclude   implicit def nsubambig1[a, b >: a]: <:!< b = null   implicit def nsubambig2[a, b >: a]: <:!< b = null    // implicit substitutions   implicit def nsub[a, b]: <:!< b = null } 

and use case:

import extendedgenerictypes._  class foo  def foobar[t](x: t)(implicit ev: t <:< foo) = "hello" def foobar[t](x: t)(implicit ev: t <:!< foo) = 5  println(foobar(new foo())) 

unfortunately, results in ambiguity, , compiler not know of 2 methods invoke. i'm looking both explanation why there ambiguity in case (as opposed other simpler cases outlined in miles' gist) , how circumvent hurdle. note need perform check on parameter level (rather defining 1 method , doing check in body) because want have different return types.

the first problem because of way you're working in repl, second foobar shadows first. if want overloaded definition, you'll need use :paste define both @ once.

that still won't want, new error message:

scala> println(foobar(new foo)) <console>:14: error: ambiguous reference overloaded definition, both method foobar of type [t](x: t)(implicit ev: egt.<:!<[t,foo])int ,  method foobar of type [t](x: t)(implicit ev: <:<[t,foo])string match argument types (foo) , expected result type               println(foobar(new foo))                       ^ 

(note i've abbreviated extendedgenerictypes because hate horizontal scrollbars.)

you can try providing <:< instance explicitly:

scala> foobar(new foo)(implicitly[foo <:< foo]) <console>:14: error: ambiguous reference overloaded definition, both method foobar of type [t](x: t)(implicit ev: egt.<:!<[t,foo])int ,  method foobar of type [t](x: t)(implicit ev: <:<[t,foo])string match argument types (foo)               foobar(new foo)(implicitly[foo <:< foo])               ^ 

so what's going on here compiler isn't going let second parameter list determine overloaded definition use. seems mean overloaded methods multiple parameter lists first parameter lists same useless. there's ticket this—at glance closest can come si-2383.

none of matters, though, because shouldn't using overloaded methods here—overloading terrible "feature" that's hangover java , breaks kinds of stuff.

there other possible approaches, though. of favorite weird scala tricks rely on fact can provide default value implicit parameter used if compiler can't find instance. if understand correctly, want this:

class foo  def foobar[t](x: t)(implicit ev: t <:< foo = null) =   option(ev).fold[either[int, string]](left(5))(_ => right("hello"))  case class bar(i: int) extends foo case class baz(i: int) 

and then:

scala> foobar(bar(13)) res0: either[int,string] = right(hello)  scala> foobar(baz(13)) res1: either[int,string] = left(5) 

note i'm using either instead of letting existence of implicit determine return type. there ways accomplish (like shapeless's first-class polymorphic function values), they're overkill in case.


update: okay, since asked it:

import shapeless._  trait lowpriorityfoobar { this: poly1 =>   implicit def anyold[t] = at[t](_ => 5) }  object foobar extends poly1 lowpriorityfoobar {   implicit def foo[t](implicit ev: t <:< foo) = at[t](_ => "hello") } 

and then:

scala> foobar(bar(13)) res6: string = hello  scala> foobar(baz(13)) res7: int = 5 

no wrapper. should think hard before taking approach, though.


update update, sake of completeness: can more directly (but more verbosely) without shapeless using dependent method types (again, you'll need use :paste define these @ once):

class foo  trait isfoomapper[i] {   type out   def apply(i: i): out }  trait lowpriorityisfoomapper {   implicit def isntfoo[a] = new isfoomapper[a] {     type out = int     def apply(a: a) = 5   } }  object isfoomapper extends lowpriorityisfoomapper {   implicit def isfoo[a](implicit ev: <:< foo) = new isfoomapper[a] {     type out = string     def apply(a: a) = "hello"   } }  def foobar[a](a: a)(implicit ifm: isfoomapper[a]) = ifm(a) 

and then:

scala> foobar(bar(13)) res0: string = hello  scala> foobar(baz(13)) res1: int = 5 

again, advanced stuff , should used caution.


Comments

Popular posts from this blog

database - VFP Grid + SQL server 2008 - grid not showing correctly -

jquery - Set jPicker field to empty value -

.htaccess - htaccess convert request to clean url and add slash at the end of the url -