Why does the following code not compile?
pub struct GenVal<T>(pub T);
impl<T> GenVal<T> {
pub fn value(&self) ->&T {
println!("Generic value() function called.");
&self.0
}
}
impl GenVal<f64> {
pub fn value(&self) ->&f64 {
println!("f64 value() function called.");
&self.0
}
}
fn main() {
let z = GenVal(3.14);
let z_val = z.value();
}
Playpen link: Rust Playground
1 Like
Okay, I think I jumped the gun on this one. Rust probably does not support partial specialization (and operator overloading). The following does not work either...
use std::fmt::Debug;
#[derive(Debug)]
struct SGen<T: Debug>(T); // Generic type `SGen`.
fn generic(s: SGen<i32>) {
println!("i32 version called. s={:?}", s);
}
fn generic<T: Debug>(s: SGen<T>) {
println!("Generic version called. s={:?}", s);
}
fn main() {
generic(SGen(1.0));
generic(SGen(6));
}
Instead you have to do the following...
use std::fmt::Debug;
#[derive(Debug)]
struct SGen<T: Debug>(T); // Generic type `SGen`.
fn gen_spec_i32(s: SGen<i32>) {
println!("i32 version called. s={:?}", s);
}
fn generic<T: Debug>(s: SGen<T>) {
println!("Generic version called. s={:?}", s);
}
fn main() {
generic(SGen(1.0));
gen_spec_i32(SGen(6));
}
So the original code can be made to work like so...
pub struct GenVal<T>(pub T);
impl<T> GenVal<T> {
pub fn value(&self) ->&T {
println!("Generic value() function called.");
&self.0
}
}
impl GenVal<f64> {
pub fn value_f64(&self) ->&f64 {
println!("f64 value() function called.");
&self.0
}
}
fn main() {
let z = GenVal(3.14);
let _z_val_g = z.value();
let _z_val = z.value_f64();
}
I ran into this problem too and figured I needed negative trait bounds to make it work, so I just ended up ditching blanket implementations with generics for now.
Perhaps the issue is that specialisation isn't applying to generic parameters; the GenVal<T> type encapsulates GenVal<f64>, because f64 is in the scope of T, so either impl is equally valid.
If I add another type parameter to GenVal, and use something different for the f64 implementation then it works because GenVal<T, ()> does not encapsulate GenVal<f64, Option<()>>. If the second type parameter is the same as the blanket impl then it fails again with the same error.
There is plan to support specialization : rfcs/0000-impl-specialization.md at impl-specialization · aturon/rfcs · GitHub. But it is not available in stable Rust yet.
Rust does not support function overloading, but it support custom operator definition by implementing Add, Sub, Mul, ... traits
I guess so but coming from a C++ background I feel C++ does the right thing in this case. It uses the most specialized implementation (GenVal<f64>::value()) from all available implementations when possible. The thinking is that the programmer will not bother writing a specialized version of a function unless it is beneficial over the generic version somehow.
Thanks for sharing the negative trait link but I still think the C++ way of doing this looks more elegant.
1 Like
Thanks for sharing this link. I think it is a better solution for this problem.