Compile Time Type Reflection w/o Any?

Hi,

Is there a mechanism for "compile time reflection" without using Any?

Specific use case: Existing project, many kloc, various layers of abstraction, generics; which means it's cumbersome to change a signature.

I now have a function, simplified:

pub fn compute(&self) -> &Geometry<T> {
    let vector3 = self.entity_transform.local_to_world_matrix.scale();
    
    // ...
}

In there vector3, which is of type Vector3<T>, might be wrong and I want to dbg! it. Unfortunately T is not Debug. What I would like to do now in pseudocode:

pub fn compute(&self) -> &Geometry<T> {
    let vector3 = self.entity_transform.local_to_world_matrix.scale();

    const if T implements Debug {
        dbg!(vector3.x, vector3.y, vector3.z);
    }

    // ...
}

Theoretically this should work and be safe since during monomorphization the compiler knows T is f32 this time, so compiling with the dbg! line is perfectly fine.

What would be the closest existing concept that is non-invasive w.r.t. to existing signatures?

Rust does not provide any functionality that allows for inspecting whether a type implements some trait whatsoever. The only exception is some nightly-only features.

Going through the pain of requiring Debug everywhere will probably be worth it in the long run, so that this sort of investigation is possible.

If you just need temporary code to diagnose an issue, you can try something like this in the nightly compiler:

#![feature(specialization)]
use std::fmt::Debug;

trait MaybeDebug {
    fn as_debug(&self) -> Option<&dyn Debug>;
}

impl<T> MaybeDebug for T {
    default fn as_debug(&self) -> Option<&dyn Debug> {
        None
    }
}

impl<T: Debug> MaybeDebug for T {
    fn as_debug(&self) -> Option<&dyn Debug> {
        Some(self)
    }
}

(Playground)

You really shouldn’t include that code in a release, though: specialization has had a long history of issues.

Hi, thanks for your suggestion. Since I knew this could only be called via f32 or f64, I eventually ended up doing it like this as that was least work:

pub fn compute(&self) -> &Geometry<T> {
    let vector3 = self.entity_transform.local_to_world_matrix.scale();

    unsafe {
        if size_of::<T>() == 4 {
            let x = transmute::<&T, &f32>(&vector3.x);
            let y = transmute::<&T, &f32>(&vector3.y);
            let z = transmute::<&T, &f32>(&vector3.z);
            dbg!(x, y, z);
        }
    }
}