It would benefit from a way to abstract over traits, but could also be done as a small extension for object safe traits today.
With a lang item with a shape like
// Ignoring the need for phantom data for ease right now
pub enum NeverForTrait<T: ?Sized> {}
One could permit impls of the form
impl<T> Iterator for NeverForTrait<dyn Iterator<Item=T>> {
type Item = T
...
}
And have that be the default coercion result and such.
It would have to be a lang item to make it the default result, and similar to how dyn safety works with how the compiler effectively autogenerates impls for impl Trait for dyn Trait
, it could also be automated (actually probably much more easily, as we don't even need vtables!). This could be especially important for trait hierarchies, as otherwise you potentially get a lot of boilerplate drilling down it, as there is no way to specify an impl which covers all the T
s you could put in that it 'should' have.
Though the fully automatic creation of those dyn impls is possibly a misfeature, and the balancing of consistency with that vs the semvar hazard of such would be an important decision.
Unfortunately, as there is no proper way to abstract over traits, while you can define new types to set what values any associated types or consts, you can't use dyn
in its current form since dyn NonObjectSafeTrait
is not allowed at all. And really using dyn
at all is a hack, since the argument to NeverForTrait
really is supposed to be a trait, not a type.
As for the broader topic, formally speaking I agree that it should prevent unused_variables
warnings. While implementation-wise any implementation of todo!()
besides a panic would be at minimum confusing, one could imagine an implementation where it uses a little time machine to actually extract your code from the future and acts as a marker to remind you to close the time loop.
This shows that the return type of !
is actually too broad, since that implementation would instead return a subfunction that takes all the other arguments and passes them in, meaning none of the variables would be used. Basically having todo!()
expand to gen_rest_probably_via_panic::<fn(Currently,Unused,Variable,Types)->ReturnType>()(unusedvariable1,unusedvariable2,unusedvariable3,unusedvariable4)
(where gen_rest_probably_via_panic
is fn<T>() -> T
which errors post-monomorphization if it can't fill in the rest of your code [which it always can because it panics, and so we don't have to worry about the time machine not coming back with code]) is the abstractly correct though very silly thing to literally do, which results in the warning being suppressed.
Rather annoyingly, you can't even do todo!()(unusedvariable1,unusedvariable2,unusedvariable3,unusedvariable4)
today. This would probably be fixed via the above improvement to defaulting, but makes the whole situation even more silly, and then more silly on top of that because we already have fn
as 'canonical' implementations for the Fn{..}
to show they are all '!
safe' and show how already integrated to the compiler they are!
As for if it should in practice suppress the warning... I think also probably yes, though perhaps there should be a warning for todo!()
itself (if there isn't already? I didn't see one by default on the playground and I didn't see any mention in the reference, but I didn't check the full list of warnings one can turn on).
Back to the specific case of !
, similar to the dyn Trait
impls for dyn-safe
traits, we could also have !-safe
traits and (more radically) ()-safe
traits. Implementing these, as they don't involve vtables, could be done far more easily in safe code. !-safe
being ones that are satisfied by !
(probably most traits, and usually with a unique implementation), and ()-safe
would be a more radical option for 'defaulting', effectively a Default
but for traits. Though the wisdom of having Iterator::next(Default::default())
compile without errors to what is (after inlining) None
is... far more debatable.