rust-num / num-traits

Numeric traits for generic mathematics in Rust
Apache License 2.0
731 stars 135 forks source link

Num::FromStrRadixErr should implement Debug #260

Closed ValouBambou closed 1 year ago

ValouBambou commented 1 year ago

I was writing a generic function for parsing one floating point number in each line of a string. And when I write the following function, I need to add this where clause for the code to compile.

use num_traits::{Float, Num};
use std::fmt::Debug;

fn parse_vec<F: Float>(content: &str) -> Vec<F>
where
    <F as Num>::FromStrRadixErr: Debug,
{
    content
        .lines()
        .map(|float| F::from_str_radix(float, 10).unwrap())
        .collect()
}

fn main() {
    let s = "1.0\n2.0\n3.0";
    let v: Vec<f32> = parse_vec(s);
    assert_eq!(v, vec![1.0, 2.0, 3.0]);
}

It's not really convenient because it propagates to all other generics I used. So, I think that enforcing FromStrRadixErr to implement debug by default is probably a good idea. But I may be wrong and there is maybe a good reason of not doing so.

cuviper commented 1 year ago

It would be a breaking change to require it now, unfortunately.

But there is also support/precedent from the standard library, e.g. FromStr::Err and TryFrom::Error have no requirements on those types.

The less-convenient fallback is that you can panic with a bespoke message about that float string, without including anything from the opaque FromStrRadixErr type.

ValouBambou commented 1 year ago

Ok that's a little bit sad but thanks for the alternative solution using FromStr it's easier and result in more convenient generics like this.

use num_traits::Float;
use std::str::FromStr;

fn parse_vec<F: Float + FromStr>(content: &str) -> Vec<F> {
    content
        .trim()
        .lines()
        .map(|line| {
            if let Ok(f) = line.parse::<F>() {
                f
            } else {
                panic!("Invalid float: {line}")
            }
        })
        .collect()
}

fn main() {
    let s = "1.0\n2.0\n3.0";
    let v: Vec<f32> = parse_vec(s);
    assert_eq!(v, vec![1.0, 2.0, 3.0]);
}