Specialization not working?


#1

I’m not sure if specialization doesn’t work for this example
due to a bug in the current implementation or due to limitations
in it’s design.

#![feature(specialization)]

trait Foo<I> { fn x() -> u32; }
impl<Leaf> Foo<Leaf> for Leaf { default fn x() -> u32 { 12u32 }}
// error conflicting implementations
impl<N, L> Foo<L> for Vec<N> where N: Foo<L> { fn x() -> u32 { 13u32 }}

fn main() {}

as a side node this also dosn’t work work without specializing the function:

#![feature(specialization)]

trait Foo<I> { }
impl<Leaf> Foo<Leaf> for Leaf { }
// error conflicting implementations
impl<N, L> Foo<L> for Vec<N> where N: Foo<L> { }

fn main() {}

#2

I think the reason is a type for N can first be written where it does not implement Foo and then a later code change implements it.
With slight addition;

impl<N, L: ::std::fmt::Display> Foo<L> for Vec<N> where N: Foo<L> { fn x() -> u32 { 13u32 }}
error[E0119]: conflicting implementations of trait `Foo<std::vec::Vec<_>>` for type `std::vec::Vec<_>`:
 --> src/main.rs:6:1
  |
4 | impl<L> Foo<L> for L { default fn x() -> u32 { 12u32 }}
  | -------------------- first implementation here
5 | // error conflicting implementations
6 | impl<N, L: ::std::fmt::Display> Foo<L> for Vec<N> where N: Foo<L> { fn x() -> u32 { 13u32 }}
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `std::vec::Vec<_>`
  |
  = note: upstream crates may add new impl of trait `std::fmt::Display` for type `std::vec::Vec<_>` in future versions

#3

@jonh, Thanks for the super fast reply.

After writing it I though about it a bit more one the
train and came to roughly the same conclusion.

What I want is a way to resolve “conflicting implementations”
where a later wild-card implementation can contain a former
one, i.e. you could say that I broaden the implementation
instead of specializing it (ironically I would even prever to
keep the impl of the first impl line adding all other from
the second).

The scary think I just became aware of is, that many
of the cases I ran into and though specialization will
solve this when available won’t be solved, I would
even say that the majority of cases won’t be solved.

Specialization still works fine for it’s typical purposes
as optimization tool but I fare that might not be what
rust needs, I fare it might need a “conflicting implementation”
solving solution which happens to also enable spcialization…

But then I have not looked into it to much so I think
I probably have to do some research before ranting
more :wink:. I just hope that rust is not actually going
into a bad direction.


#4

I’d have expected your first code snippet to compile. Vec<N> is more specific than the blanket impl and should resolve the overlap. It looks like the compiler is worried about the generic parameter of Foo - if you make it non-generic, the code compiles. It seems like it thinks you can end up with duplicate Foo<...> across the two impls, but I don’t understand why that’s relevant. I’ve also lost track of where specialization stands today, what works, what doesn’t temporarily vs permanently, etc :slight_smile:


#5

Just for clarity:

Foo<L> for Vec<N>, N: Foo<L>

conflicts with:

Foo<L> for L

iff L == Vec<N> which inlined turns into:

Foo<Vec<N>> for Vec<N>, N: Foo<L>

Which could be seen as:

Foo<Leaf> for Leaf, <some_constraint>

And maybe might count a specialization?
The problem is if we see it like that non of the
types are more concrete it just has another
constraint to it.


#6

There’s overlap but I’d think Vec<N> is always more specific than a generic Leaf type. Isn’t that the point of specialization? :slight_smile: