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.
[Isn't relevant here.]
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.
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:
- 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?
- Can someone provide a reading of the spec that accounts for this behavior?
- 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.