Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala view application puzzler

Say we have the following two traits:

trait Foo[A] { def howMany(xs: List[A]) = xs.size }
trait Bar

And an implicit conversion from the second to the first:

implicit def bar2foo[A](bar: Bar) = new Foo[A] {}

We create a Bar and a list of integers:

val bar = new Bar {}
val stuff = List(1, 2, 3)

Now I'd expect the following to work:

bar howMany stuff

But it doesn't:

scala> bar howMany stuff
<console>:13: error: type mismatch;
 found   : List[Int]
 required: List[A]
              bar howMany stuff
                          ^

So we go to the spec, which has this to say (emphasis in bold is mine):

Views are applied in three situations.

  1. [Isn't relevant here.]

  2. In a selection e.m with e of type T, if the selector m does not denote a member of T. In this case, a view v is searched which is applicable to e and whose result contains a member named m. The search proceeds as in the case of implicit parameters, where the implicit scope is the one of T. If such a view is found, the selection e.m is converted to v(e).m.

  3. In a selection e.m(args) with e of type T, if the selector m denotes some member(s) of T, but none of these members is applicable to the arguments args. In this case a view v is searched which is applicable to e and whose result contains a method m which is applicable to args. The search proceeds as in the case of implicit parameters, where the implicit scope is the one of T. If such a view is found, the selection e.m is converted to v(e).m(args).

So we try the following, thinking it must be too absurd to work:

trait Foo[A] { def howMany(xs: List[A]) = xs.size }
trait Bar { def howMany = throw new Exception("I don't do anything!") }

implicit def bar2foo[A](bar: Bar) = new Foo[A] {}

val bar = new Bar {}
val stuff = List(1, 2, 3)

But it does (on both 2.9.2 and 2.10.0-RC2, at least):

scala> bar howMany stuff
res0: Int = 3

This leads to some really strange behavior, as for example in this workaround for this problem.

I have three (closely related) questions:

  1. Is there a straightforward way (i.e., one that doesn't involve adding fake methods with the appropriate name) to have the view applied correctly in the original case above?
  2. Can someone provide a reading of the spec that accounts for this behavior?
  3. Assuming this is the intended behavior, does it make any sense at all?

I'd also appreciate any links to previous discussions of this issue—I haven't been having much luck with Google.

like image 415
Travis Brown Avatar asked Nov 22 '12 14:11

Travis Brown


2 Answers

For everyone's reference, this could only be a bug. The way you know that is the error message:

<console>:13: error: type mismatch;
 found   : List[Int]
 required: List[A]

List[A] is not a real type - it is List applied to its own type parameter. That is not a type which can be required since it is not a type which can be expressed.

[Edit - it's too early, who knows what I'm talking about. Ignore the above, but you can still follow the link.]

The relevant ticket for this is https://issues.scala-lang.org/browse/SI-6472 .

like image 184
psp Avatar answered Oct 26 '22 03:10

psp


This seems like a bug so my answers are:

  1. search for a simliar bug reported against the Scala compiler and if not found, report a new bug https://issues.scala-lang.org/
  2. that part of the spec doesn't seem to matter in this case as it doesn't talk about type inference
  3. doesn't make any sense to me

PS. In 2.8.1 your workaround of adding the dummy method to Bar doesn't make it compile.

like image 27
Erkki Lindpere Avatar answered Oct 26 '22 02:10

Erkki Lindpere