Expected output:
Actual output: default
Expected output:
Actual output: default
I didn't dig in depth, but the implementation getting called that prints default is the implementation for dyn Op<'_> + '_
. Playground. Note that the bounds on that default implementation are met by dyn Op<'_> + '_
.[1]
Incidentally my real answer is "don't use feature(specialization)
; not only is it incomplete, it's known to be unsound."
There are some open questions about how this should interact with the compiler-provided implementation. ↩︎
Mainly, doing a search-and-replace of s/dyn Op/dyn Targets/g
fixes the issue:
dyn
you probably want to be dyn
amically dispatching the .targets()
method (in C++ parlance, call it as a virtual
method);dyn Op…
does not include such a method in its trait
hierarchy.Targets
for T : ?Sized + Op…
did cover the dyn Op…
type, resulting in a statically dispatched call to the (default
) fn targets
in that impl
.I also agree that you should very much avoid using specialization
, especially if you're not dealing with : 'static
types
Since you'll probably want to stick to dyn Op…
since you want to be expressing that these things are Op
erands or Op
erations, another way not to have to replace dyn Op…
with dyn Targets
is by having Targets
be a supertrait of trait Op
, so that the methods of the former be part of the latter, including in the dyn
amic dispatch hierarchy.
From there, you can avoid the need for specialization
at the cost of a very tiny bit of red tape:
// no more `: Op<'a>` here.
// v
pub trait Targets<'a> {
fn targets(&self) -> Vec<LabelOrNext<'a>> {
// "default" impl here.
println!("default");
vec![]
}
}
// vvvvvvvvvvvvv
pub trait Op<'a> : ::core::fmt::Debug + Targets<'a> {
// ...
}
fn targets
inside of Op<'_>
)Now, any concrete implementation of Op<'a>
would need a companion concrete implementation of Targets<'_>
(or of the fn targets
method):
For your concrete Br<'_>
type, you write it as usual;
For the other types, you just need to "tag/acknowledge" it for the above "default impl" to be used:
struct MyOtherOp<…> {
…
}
impl<'a> Op<'a> for MyOtherOp<…> {
…
}
// 👇
impl<'a> Targets<'a> for MyOtherOp<…> {} // <- no need for a body here!