- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
2.8.0.RC7 implicit confusion
Tue, 2010-07-13, 06:47
Howdy,
I've got a companion object:
object MQuery { implicit def mqToJObj(in: MQuery): JObject = in.jvalue implicit def jvToQBase[Q <: QBase: Manifest](in: MQuery): Q = in.jvalue.extract[Q]
In another class, I've got a method:
def find[T](query: MQuery)(implicit f: MQuery => T): Stream[T] =
I call the find method as (note that Frog <: QBase): println(con.find[JObject]("moo" -> 13).toList) println(con.find[Frog]("moose" -> true).toList)
And receive:
Why is the implicit ambiguous? JValue is not a subclass of QBase. Why is the jvToQBase implicit considered for find[JObject]?
Thanks,
David
--
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890
Follow me: http://twitter.com/dpp
Blog: http://goodstuff.im
Surf the harmonics
I've got a companion object:
object MQuery { implicit def mqToJObj(in: MQuery): JObject = in.jvalue implicit def jvToQBase[Q <: QBase: Manifest](in: MQuery): Q = in.jvalue.extract[Q]
In another class, I've got a method:
def find[T](query: MQuery)(implicit f: MQuery => T): Stream[T] =
I call the find method as (note that Frog <: QBase): println(con.find[JObject]("moo" -> 13).toList) println(con.find[Frog]("moose" -> true).toList)
And receive:
[info] Compiling main sources... [error] /home/dpp/proj/mongo/src/main/scala/net/stambecco/mongo/Dude.scala:35: ambiguous implicit values: [error] both method jvToQBase in object MQuery of type [Q <: org.stambecco.QBase](in: net.stambecco.mongo.MQuery)(implicit evidence$1: Manifest[Q])Q [error] and method mqToJObj in object MQuery of type (in: net.stambecco.mongo.MQuery)net.liftweb.json.JsonAST.JObject [error] match expected type (net.stambecco.mongo.MQuery) => net.liftweb.json.JsonAST.JObject [error] println(con.find[JObject]("moo" -> 13).toList)[error] ^ [error] one error found[info] == compile ==
Why is the implicit ambiguous? JValue is not a subclass of QBase. Why is the jvToQBase implicit considered for find[JObject]?
Thanks,
David
--
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890
Follow me: http://twitter.com/dpp
Blog: http://goodstuff.im
Surf the harmonics
Tue, 2010-07-13, 11:07
#2
Re: 2.8.0.RC7 implicit confusion
On Tue, Jul 13, 2010 at 7:47 AM, David Pollak <feeder.of.the.bears@gmail.com> wrote:
Why is the implicit ambiguous? JValue is not a subclass of QBase. Why is the jvToQBase implicit considered for find[JObject]?I tried to reproduce your example, but am missing too much context.
My stab in the dark would be the Manifest: the combination of Manifest[T], type inference for T and other implicits that involve T does not work well (see my comment on http://suereth.blogspot.com/2010/06/preserving-types-and-differing-subclass.html)
hthadriaan
Tue, 2010-07-13, 14:27
#3
Re: 2.8.0.RC7 implicit confusion
On Tue, Jul 13, 2010 at 2:59 AM, Adriaan Moors <adriaan.moors@epfl.ch> wrote:
On Tue, Jul 13, 2010 at 7:47 AM, David Pollak <feeder.of.the.bears@gmail.com> wrote:
Why is the implicit ambiguous? JValue is not a subclass of QBase. Why is the jvToQBase implicit considered for find[JObject]?I tried to reproduce your example, but am missing too much context.
My stab in the dark would be the Manifest: the combination of Manifest[T], type inference for T and other implicits that involve T does not work well (see my comment on http://suereth.blogspot.com/2010/06/preserving-types-and-differing-subclass.html)
Okay... I boiled it down:
trait Flutter
object Moose { implicit def moo[Q <: Flutter](in: Int): Q = null.asInstanceOf[Q]
def some[Q](in: Int)(implicit f: Int => Q): Q = f(in)
val s: String = some(44) // this should not compile }
It seemed the the type bound on the return type is being ignored. I think this is different from 2781/3346.
hthadriaan
--
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890
Follow me: http://twitter.com/dpp
Blog: http://goodstuff.im
Surf the harmonics
Tue, 2010-07-13, 14:37
#4
Re: 2.8.0.RC7 implicit confusion
compiling with -Xprint:typer shows you why it type checks:trait Flutter
object Moose { implicit def moo[Q <: Flutter](in: Int): Q = null.asInstanceOf[Q]
def some[Q](in: Int)(implicit f: Int => Q): Q = f(in)
val s: String = some(44) // this should not compile }
It seemed the the type bound on the return type is being ignored. I think this is different from 2781/3346.
val s: String = some[String](44){ (in: Int) => moo[Nothing](in) }
because => is covariant in its second type parameter, Int => Nothing is a subtype of Int => String
my guess would be you need non-parametric versions of moo at concrete types for Q:implicit def mooFlutter1(int: Int) : Flutter1 = ...implicit def mooFlutter2(int: Int) : Flutter2 = ...
cheersadriaan
Tue, 2010-07-13, 14:57
#5
Re: 2.8.0.RC7 implicit confusion
On Tue, Jul 13, 2010 at 6:31 AM, Adriaan Moors <adriaan.moors@epfl.ch> wrote:
compiling with -Xprint:typer shows you why it type checks:trait Flutter
object Moose { implicit def moo[Q <: Flutter](in: Int): Q = null.asInstanceOf[Q]
def some[Q](in: Int)(implicit f: Int => Q): Q = f(in)
val s: String = some(44) // this should not compile }
It seemed the the type bound on the return type is being ignored. I think this is different from 2781/3346.
val s: String = some[String](44){ (in: Int) => moo[Nothing](in) }
because => is covariant in its second type parameter, Int => Nothing is a subtype of Int => String
But the compiler isn't enforcing that Nothing is being returned from the function (i.e., an exception is thrown), so that seems like a problem because you're going to wind up with class case exception in the string assignment.
Put another way, in this case, I want to explicitly exclude Nothing from the type bounds. Is there any way to do this?
my guess would be you need non-parametric versions of moo at concrete types for Q:implicit def mooFlutter1(int: Int) : Flutter1 = ...implicit def mooFlutter2(int: Int) : Flutter2 = ...
cheersadriaan
--
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890
Follow me: http://twitter.com/dpp
Blog: http://goodstuff.im
Surf the harmonics
Tue, 2010-07-13, 15:07
#6
Re: 2.8.0.RC7 implicit confusion
On Tue, Jul 13, 2010 at 6:48 AM, David Pollak <feeder.of.the.bears@gmail.com> wrote:
On Tue, Jul 13, 2010 at 6:31 AM, Adriaan Moors <adriaan.moors@epfl.ch> wrote:compiling with -Xprint:typer shows you why it type checks:trait Flutter
object Moose { implicit def moo[Q <: Flutter](in: Int): Q = null.asInstanceOf[Q]
def some[Q](in: Int)(implicit f: Int => Q): Q = f(in)
val s: String = some(44) // this should not compile }
It seemed the the type bound on the return type is being ignored. I think this is different from 2781/3346.
val s: String = some[String](44){ (in: Int) => moo[Nothing](in) }
because => is covariant in its second type parameter, Int => Nothing is a subtype of Int => String
But the compiler isn't enforcing that Nothing is being returned from the function (i.e., an exception is thrown), so that seems like a problem because you're going to wind up with class case exception in the string assignment.
Put another way, in this case, I want to explicitly exclude Nothing from the type bounds. Is there any way to do this?
Or put yet another way:
def foo() { val x: Nothing = null.asInstanceOf[Nothing] println("Foo")}
def bar(): Nothing = null.asInstanceOf[Nothing]
def baz() { val x = bar() println("Baz")}
def m() { bar() match { case _ => println("Hello") } }
foo()baz()m()
I've just created a method that returns Nothing, yet it returns normally (it does not throw an exception). This seems like a deeper problem. :-)
my guess would be you need non-parametric versions of moo at concrete types for Q:implicit def mooFlutter1(int: Int) : Flutter1 = ...implicit def mooFlutter2(int: Int) : Flutter2 = ...
cheersadriaan
--
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890
Follow me: http://twitter.com/dpp
Blog: http://goodstuff.im
Surf the harmonics
--
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890
Follow me: http://twitter.com/dpp
Blog: http://goodstuff.im
Surf the harmonics
Tue, 2010-07-13, 18:57
#7
Re: 2.8.0.RC7 implicit confusion
On Tue, Jul 13, 2010 at 4:02 PM, David Pollak <feeder.of.the.bears@gmail.com> wrote:
I've just created a method that returns Nothing, yet it returns normally (it does not throw an exception). This seems like a deeper problem. :-)casts are evil, is all I can say, I'm afraid
Well, maybe I could say something like: Nothing does not guarantee the method will not return, it just means it might not. Just like a throws clause does not mean all the listed exceptions will be thrown. Casts are the ultimate escape hatch: they overrule the nice reasoning you can do by solely looking at the types (def identity[T](x: T): T --> that method can only return x right? well, that's what the free theorem says in an ideal world (i.e., Haskell -- but even there appearances can be deceiving), but it may also throw an exception, loop, cast any reference it pleases into a T, set your computer on fire, upset your neighbours, spook your dog, tweet embarrassing things using your account,...)
adriaan
Tue, 2010-07-13, 19:07
#8
Re: 2.8.0.RC7 implicit confusion
Hello,
the problem with null and Nothing is already known (I'll hope).
Here my old example:
scala> val narr= Array.ofDim(1)
narr: Array[Nothing] = Array(null)
scala> println(narr(0))
null
def foo(x: Any) = "Hello"
foo: (x: Any)java.lang.String
scala> foo(narr(0))
res15: java.lang.String = Hello
regards
friedrich
Tue, 2010-07-13, 20:07
#9
Re: 2.8.0.RC7 implicit confusion
On Tue, Jul 13, 2010 at 10:50 AM, Adriaan Moors <adriaan.moors@epfl.ch> wrote:
On Tue, Jul 13, 2010 at 4:02 PM, David Pollak <feeder.of.the.bears@gmail.com> wrote:
I've just created a method that returns Nothing, yet it returns normally (it does not throw an exception). This seems like a deeper problem. :-)casts are evil, is all I can say, I'm afraid
Well, maybe I could say something like: Nothing does not guarantee the method will not return, it just means it might not.
I believe that it the compiler should guarantee that a method with return type Nothing should not return except to throw an exception.
I believe that the following code:
def foo(nuthin: Nothing): Unit = {}
Should be a compile-time error.
I believe there should be a way to specify that the type X <: Foo must be an instantiatable class rather than potentiality being Nothing.
I believe that a choice between an implicit where the compiler has to infer Nothing and the compiler can find a concrete method with a matching return type, there should not be any ambiguity.
I understand why Nothing exists and how it makes things like Nil possible, but failure to keep Nothing bounded in will turn it into the Scala equivalent of null. "Oh yeah, Nothing will solve that... it might lead to a runtime problem, but let's not worry about it at compile time."
Sorry for the rant, but digging into this issue raises a lot of issues in my mind.
Just like a throws clause does not mean all the listed exceptions will be thrown. Casts are the ultimate escape hatch: they overrule the nice reasoning you can do by solely looking at the types (def identity[T](x: T): T --> that method can only return x right? well, that's what the free theorem says in an ideal world (i.e., Haskell -- but even there appearances can be deceiving), but it may also throw an exception, loop, cast any reference it pleases into a T, set your computer on fire, upset your neighbours, spook your dog, tweet embarrassing things using your account,...)
adriaan
--
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890
Follow me: http://twitter.com/dpp
Blog: http://goodstuff.im
Surf the harmonics
Wed, 2010-07-14, 18:47
#10
Re: 2.8.0.RC7 implicit confusion
I believe that it the compiler should guarantee that a method with return type Nothing should not return except to throw an exception.that would mean casting to Nothing needed to be verbotensince casts are by nature unsafe, why bother making them a little safer?
If you have a pressing need to enforce this in your code, I think a compiler plugin could do that pretty easily
I believe that the following code:we could certainly emit a dead code warning, but, again, I don't think it warrants changing the spec
def foo(nuthin: Nothing): Unit = {}
Should be a compile-time error.
there are many more ways you can prevent some type from having instances, and the only case where we make sure you didn't do that by accident is in class definitions: you need to flag them as abstract explicitly to make sure you didn't accidentally define a type that can't be instantiated
here's an example that just reeks of virtual classes and the thorniness they entail
trait Base { type T def make: T}
trait X extends Base { type T <: String}
trait Y extends Base { type T <: Int}
def makeWithXY(xy: X with Y): xy.T = xy.make
our glorious 2.8.0 compiler thinks this is perfectly respectable code
it's pretty hard to actually come up with a reasonable argument for makeWithXY, though...
should `X with Y` be an invalid type? X is valid. Y is valid. The possibility of their mixin composition not being considered valid again complicates the spec -- but maybe we will have to do this eventually -- this is something we're working on
I believe there should be a way to specify that the type X <: Foo must be an instantiatable class rather than potentiality being Nothing.I agree that would be very interesting (and in fact, the formal calculus in my thesis allowed types to be bounded that way)(also, I think this could be part of an extension to support virtual classes)
I believe that a choice between an implicit where the compiler has to infer Nothing and the compiler can find a concrete method with a matching return type, there should not be any ambiguity.oh covariance, why do you complicate our lives so?
I understand why Nothing exists and how it makes things like Nil possible, but failure to keep Nothing bounded in will turn it into the Scala equivalent of null. "Oh yeah, Nothing will solve that... it might lead to a runtime problem, but let's not worry about it at compile time."well, it's really the cast that did it, as usual
that said, I think it would be useful to be able to express the opposite of type equality, =/:=, and subtyping, </:< I'm not sure we can express this in 2.8 using the same trick we use for <:< and =:= -- I'm still thinking about it, though(I have variations on implicit search lying around in other branches that would allow this, I think)
regards,adriaan
Fri, 2010-07-16, 07:07
#11
Re: 2.8.0.RC7 implicit confusion
Using some intentional ambiguity and mharrah's Up, one can be express [1]:
def excludeDemo[A](a: A)(implicit c: NotContained[Int :: Boolean ::
Double :: HNil, A]) = a
excludeDemo("a")
excludeDemo(3) //fails
I take credit for being the conduit through which Josh Suereth's nice
idea flowed to someone capable of implementing it cleanly!
-jason
[1] http://github.com/harrah/up/commit/aa00b48fd1e4e141235d305e5e877fb74f076...
On Wed, Jul 14, 2010 at 7:25 PM, Adriaan Moors wrote:
>> I believe there should be a way to specify that the type X <: Foo must be
>> an instantiatable class rather than potentiality being Nothing.
> that said, I think it would be useful to be able to express the opposite of
> type equality, =/:=, and subtyping, I'm not sure we can express this in 2.8 using the same trick we use for <:<
> and =:= -- I'm still thinking about it, though
> (I have variations on implicit search lying around in other branches that
> would allow this, I think)
Fri, 2010-07-16, 09:57
#12
Re: 2.8.0.RC7 implicit confusion
Jason Zaugg skrev 2010-07-16 07:59:
> Using some intentional ambiguity and mharrah's Up, one can be express [1]:
>
> def excludeDemo[A](a: A)(implicit c: NotContained[Int :: Boolean ::
> Double :: HNil, A]) = a
> excludeDemo("a")
> excludeDemo(3) //fails
>
> I take credit for being the conduit through which Josh Suereth's nice
> idea flowed to someone capable of implementing it cleanly!
Hmm, that should be a TList instead of a HList IMHO :) (see
http://jnordenberg.blogspot.com/2009/09/type-lists-and-heterogeneously-t...).
/Jesper Nordenberg
Fri, 2010-07-16, 13:17
#13
Re: 2.8.0.RC7 implicit confusion
He's got one of those [1], too. Not sure why he picked HList instead,
TList seems a better fit.
-jason
[1] http://github.com/harrah/up/blob/master/TList.scala
On Fri, Jul 16, 2010 at 10:48 AM, Jesper Nordenberg wrote:
> Jason Zaugg skrev 2010-07-16 07:59:
>>
>> Using some intentional ambiguity and mharrah's Up, one can be express [1]:
>>
>> def excludeDemo[A](a: A)(implicit c: NotContained[Int :: Boolean ::
>> Double :: HNil, A]) = a
>> excludeDemo("a")
>> excludeDemo(3) //fails
>>
>> I take credit for being the conduit through which Josh Suereth's nice
>> idea flowed to someone capable of implementing it cleanly!
>
> Hmm, that should be a TList instead of a HList IMHO :) (see
> http://jnordenberg.blogspot.com/2009/09/type-lists-and-heterogeneously-t...).
Fri, 2010-07-16, 13:57
#14
Re: Re: 2.8.0.RC7 implicit confusion
On Friday 16 July 2010, Jason Zaugg wrote:
> He's got one of those [1], too. Not sure why he picked HList instead,
> TList seems a better fit.
Probably because he forgot he had a TList. The HList type is never used for a value, though, so there wouldn't be anything gained by using a TList.
-Mark
> -jason
>
> [1] http://github.com/harrah/up/blob/master/TList.scala
>
> On Fri, Jul 16, 2010 at 10:48 AM, Jesper Nordenberg wrote:
> > Jason Zaugg skrev 2010-07-16 07:59:
> >>
> >> Using some intentional ambiguity and mharrah's Up, one can be express [1]:
> >>
> >> def excludeDemo[A](a: A)(implicit c: NotContained[Int :: Boolean ::
> >> Double :: HNil, A]) = a
> >> excludeDemo("a")
> >> excludeDemo(3) //fails
> >>
> >> I take credit for being the conduit through which Josh Suereth's nice
> >> idea flowed to someone capable of implementing it cleanly!
> >
> > Hmm, that should be a TList instead of a HList IMHO :) (see
> > http://jnordenberg.blogspot.com/2009/09/type-lists-and-heterogeneously-t...).
>
>
Smells like:
https://lampsvn.epfl.ch/trac/scala/ticket/2781
Stab in the dark:
implicit def jvToQBase[Q](in: MQuery)(implicit ev: Q <:< QBase, m:
Manifest[Q]) = ...
-jason
On Tue, Jul 13, 2010 at 7:47 AM, David Pollak
wrote:
> Howdy,
> I've got a companion object:
> object MQuery {
> implicit def mqToJObj(in: MQuery): JObject = in.jvalue
> implicit def jvToQBase[Q <: QBase: Manifest](in: MQuery): Q =
> in.jvalue.extract[Q]
>
> In another class, I've got a method:
> def find[T](query: MQuery)(implicit f: MQuery => T): Stream[T] =
> I call the find method as (note that Frog <: QBase):
> println(con.find[JObject]("moo" -> 13).toList)
> println(con.find[Frog]("moose" -> true).toList)
> And receive:
>
> [info] Compiling main sources...
> [error]
> /home/dpp/proj/mongo/src/main/scala/net/stambecco/mongo/Dude.scala:35:
> ambiguous implicit values:
> [error] both method jvToQBase in object MQuery of type [Q <:
> org.stambecco.QBase](in: net.stambecco.mongo.MQuery)(implicit evidence$1:
> Manifest[Q])Q
> [error] and method mqToJObj in object MQuery of type (in:
> net.stambecco.mongo.MQuery)net.liftweb.json.JsonAST.JObject
> [error] match expected type (net.stambecco.mongo.MQuery) =>
> net.liftweb.json.JsonAST.JObject
> [error] println(con.find[JObject]("moo" -> 13).toList)
> [error] ^
> [error] one error found
> [info] == compile ==
>
> Why is the implicit ambiguous? JValue is not a subclass of QBase. Why is
> the jvToQBase implicit considered for find[JObject]?
> Thanks,
> David
> --
> Lift, the simply functional web framework http://liftweb.net
> Beginning Scala http://www.apress.com/book/view/1430219890
> Follow me: http://twitter.com/dpp
> Blog: http://goodstuff.im
> Surf the harmonics
>