As @user4815162342 commented, using specialization, this is possible.
I'll provide a slightly different approach from what they specified in their comment, to keep the same if ... { ... } setup that you had in your original code.
The idea is to have a trait AsMaybeDebug with an associated type Debug, which always implements Debug and a function to go from &Self to Option<&Self::Debug>:
trait AsMaybeDebug {
type Debug: Debug;
fn as_maybe_debug(&self) -> Option<&Self::Debug>;
}
After this we make a default impl for all T, with the debug type being !, the never type, and always return None.
impl<T> AsMaybeDebug for T {
default type Debug = !;
default fn as_maybe_debug(&self) -> Option<&Self::Debug> {
None
}
}
Instead of the never type, you could choose any type that always implemented Debug but still returning None.
Afterwards we specialize for T: Debug by returning Self:
impl<T: Debug> AsMaybeDebug for T {
type Debug = Self;
fn as_maybe_debug(&self) -> Option<&Self::Debug> {
Some(self)
}
}
Finally in test we just call as_maybe_debug and check if T: Debug
fn test<T: Eq>(a: T, b: T){
if a != b {
println!("Not equal!");
if let (Some(a), Some(b)) = (a.as_maybe_debug(), b.as_maybe_debug()) {
println!("{:?} != {:?}", a, b);
}
}
}
You can check in the playground both that it works and that the assembly generated for test_non_debug doesn't have any debugging calls, only the single call to std::io::_print.
It unfortunately isn't possible to retrieve the original a or b inside the if after calling as_maybe_debug.
This is due to <Self as AsMaybeDebug>::Debug not being
convertible back to Self.
This can be fixed, but not easily as it requires updates from the standard library.
Requiring AsMaybeDebug::Debug: AsRef<Self> doesn't work for 2 reasons:
-
- There is no
impl<T> AsRef<T> for T yet, this is due to specialization still being incomplete, I assume.
-
- There is no
impl<T> AsRef<T> for ! yet. Not sure if this impl can be made even with specialization or not, but it would be required.
Also, although the specialization can be unsound, I believe that the trait and it's impls cannot be used for unsoundness, you would need a specific setup to be able to generate unsoundness from it, which this lacks.