Description
The interaction between implicit borrows and typeclasses is currently problematic and inconsistent.
Suppose we have the following interface, an implementation of it for vector slices, and a function that is parameterized over the typeclass:
iface iterable<A> {
fn iterate(blk: fn(A) -> bool);
}
impl vec/&<A> of iterable<A> for &[const A] {
fn iterate(f: fn(A) -> bool) {
vec::each(self, f);
}
}
fn print<A, T: iterable<A>>(x: T) {
for x.iterate() |x| { log(error, x); }
}
The following code works since x
will be implicitly borrowed
fn main() {
let x = ~[1,2,3];
for x.iterate() |x| { log(error, x) }
}
This is because add_candidates_from_scope
in method.rs uses can_mk_assignty
when matching against impls, which will do a borrow to convert x
to a slice.
However, the following code does not work:
fn main() {
let x = ~[1,2,3];
print(x);
}
It will fail to find an implementation of iterable
for [int]/~
. This is because lookup_vtable
in vtable.rs uses mk_subty
when matching against impls. I think that lookup_vtable
basically has to use subtyping and not type assignability: typeclass constraints need not correspond to just the type of an argument expression that we can perform a borrow on.
To make matters worse, we can't work around this by just writing impl
s for ~[A]
, since then the first example would fail with an error about multiple methods in scope.
I think probably the right thing to do is to not do implicit borrows on method calls, but I'm not sure.