Using manual and macro implementations for Debug together

Hello world,

I have the next error:
implementation of 'Debug' is not general enough 'Debug' would have to be implemented for the type for<'r> fn(&'r Vec<Vec<f32>>) -> Vec<f32> ...but 'Debug' is actually implemented for the type 'fn(&'0 Vec<Vec<f32>>) -> Vec<f32>', for some specific lifetime '0 whilst using

#[derive(Derivative)]
#[derivative(Debug, Default)]

macros at my project. More specifically, I have a struct:

pub struct Algorithm {
    #[derivative(Default(value = "10"))]
    n: usize,
    #[derivative(Default(value = "2"))]
    m: usize,
    #[derivative(Default(value = "fold_2d_function"))]
    score_function: fn(&Vec<Vec<f32>>) -> Vec<f32>,
    best_scores: Vec<Vec<f32>>,
}

where I want to assign default params to each of the rows, thats why I'm using Derivative. However, the error made by default Debug implementation for score_function.

I tried smth like this:

fn obfuscated_formatter(arr: &fn(&Vec<Vec<f32>>) -> Vec<f32>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    write!(f, "{:?}", arr)
}

pub struct Algorithm {
    #[derivative(Default(value = "10"))]
    n: usize,
    #[derivative(Default(value = "2"))]
    m: usize,
    #[derivative(Default(value = "fold_2d_function"), Debug(format_with = "obfuscated_formatter"))]
    score_function: fn(&Vec<Vec<f32>>) -> Vec<f32>,
    best_scores: Vec<Vec<f32>>,
}

But it fails however, with the same error. How can I improve it?

Huh, that is surprising. Reduced:

#[derive(Debug)]
struct S {
    f: fn(&Vec<Vec<f32>>)
}

I'd be a little surprised if there wasn't an issue already, but didn't find one offhand.


Anyway, derive is limited in other senses too. The workaround is generally to implement it yourself. I'm not sure if derivative would require special steps.

Thanks, but if I implement it by myself, I need to implement it for every field of my struct? Because I have like 20 fields, and my implementation will be like

impl fmt::Debug for Algorithm {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Algorithm")
            .field("score_function", &&self.score_function)
            .field("a", &self.a)
            .field("b", &self.b)
..............
            .finish()
    }
}

or I can use #[derive(Debug)] with manual implementation for not filling all of the fields?

This is a problem even with manual implementation.

The problem is that Debug for fn pointers is implemented using generics (impl<T> fmt::Debug for fn(T)) and this doesn't allow late bound lifetimes.

So, is there some workaround? Not to use pointer to a function, that's all?

If it's only this one field preventing the derive, perhaps create a separate type for it (newtype) and impl Debug with a shallow representation, maybe using a string that consists of the field name and its type (i32). This will allow you to derive the parent struct with the many fields that you are describing.

3 Likes

If that's you're manual implementation, sure -- that's basically just an expansion of what the macro does. I meant print something for the value yourself. This works, but may or may not be useful. @EdmundsEcho's recommendation is a good one -- you could store the newtype and derive, or you could have a custom implementation where you pass some "temp" type.

1 Like

Thanks for advice.
I tried to implement my own type via newtype, since deriving Default gives an error as well.
But I've got another error:

pub fn himmelblau(x: f32, y: f32) -> f32 {
    f32::powf(x * x + y - 11., 2.) + f32::powf(x + y * y - 7., 2.)
}

pub fn fold_2d_function(x: &Vec<Vec<f32>>) -> Vec<f32> {
    x.iter()
        .map(|row| {
            himmelblau(
                row[0], 
                row[1], 
            )
        })
        .collect::<Vec<f32>>()
}

struct NewType{
    f: fn(&Vec<Vec<f32>>)
}

impl fmt::Debug for NewType {
    fn fmt<'s>(&'s self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let lower_rank: fn(&'s Vec<Vec<f32>>) = self.f;
        f.debug_struct("NewType")
            .field("f", &lower_rank)
            .finish()
    }
}

impl Default for NewType {
    fn default() -> Self {
        NewType {
            f: fold_2d_function as fn(&Vec<Vec<f32>>) -> Vec<f32>,
        }
    }
}

#[derive(Derivative)]
#[derivative(Debug, Default)]
struct S {
    n:f32,
    m:f32,
    f:NewType
}

gives me

= note: expected fn pointer 'for<'r> fn(&'r Vec<Vec<f32>>)'
              found fn pointer 'for<'r> fn(&'r Vec<Vec<f32>>) -> Vec<f32>'' 

Here I use himmelblau function as a "cost" function. And fold_2d_function for explicit folding of Vec<Vec<f32>>.

Perhaps I need to explicitly pass some Vec<Vec<f32>> folded with some default values (zeros or smth)?

This means that lower_rank has the wrong type - the return type of function is part of its type, you can't omit it.

when I change type to

fn(&'s Vec<Vec<f32>>) -> Vec<f32>

I have another error connected with lifetimes:

 = note: expected fn pointer `fn(&'s Vec<Vec<f32>>) -> Vec<f32>`
              found fn pointer `for<'r> fn(&'r Vec<Vec<f32>>)`

Seems I solved it, just need to explicitly specify returned type:

struct SubjectFunctionType{
    pub subject_function: fn(&Vec<Vec<f32>>)-> Vec<f32>,
}
impl fmt::Debug for SubjectFunctionType {
    fn fmt<'s>(&'s self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let lower_rank: fn(&'s Vec<Vec<f32>>) -> Vec<f32> = self.subject_function;
        f.debug_struct("SubjectFunctionType")
            .field("subject_function", &&lower_rank)
            .finish()
    }
}
impl Default for SubjectFunctionType {
    fn default() -> Self {
        SubjectFunctionType {
            subject_function: fold_2d_function as fn(&Vec<Vec<f32>>) -> Vec<f32>,
        }
    }
}

There was born another question though (connected with folding vec of vecs some more elegant way), but I'll better create another topic for this.