Function that returns different type of value depending on type annotation

I want to have something like

give_five::<String>(); // returns "five"
give_five::<i32>(); // returns 5
give_five::<f32>(); // return 5.0

I tried to write but it doesn't work. I have no clue how to do it.

fn give_five<String>() -> String {
    String::from("five")
}
fn give_five<i32>() -> i32 {
    5
}
fn give_five<f32>() -> f32 {
    5.0
}

The only way to do overloading in Rust is to use traits.

trait CanGiveFive {
    fn give_five() -> Self;
}

impl CanGiveFive for String {
    fn give_five() -> String {
        "5".to_string()
    }
}
impl CanGiveFive for i32 {
    fn give_five() -> i32 {
        5
    }
}
impl CanGiveFive for f32 {
    fn give_five() -> f32 {
        5.0
    }
}

fn give_five<T: CanGiveFive>() -> T {
    T::give_five()
}

playground

3 Likes

I don't think you can do that with functions today. You can with structs, though, if that's any comfort.

Can you show how?

This is allowed (though admittedly one of Rust's best-kept secrets):

struct Foo<T> {
    inner: T,  // Could be a PhantomData<T> as well
}

impl Foo<String> {
    fn give_five() -> String {
        "5" .to_string()
    }
}

impl Foo<i32> {
    fn give_five() -> i32 {
        5
    }
}

impl Foo<f32> {
    fn give_five() -> f32 {
        5.0
    }
}

And then you can do Foo<i32>::give_five().

1 Like

Note that this works for the same reason you could do this:

struct A;
struct B;
impl A {
    fn give_five() -> i32 { 5 }
}
impl B {
    fn give_five() -> f32 { 5.0 }
}

The functions are defined on different types, so they do not collide.

Exactly. But ever since I learned about this feature, I always found it funny that you can have divergent impl blocks for generic structs (which could become even more powerful with specialization), but not divergent definitions for generic functions.

Tried with phantom data. Thanks for the help guys.

struct Five<T>(PhantomData<T>);

impl Five<i32> {
    fn give() -> i32 {
        5
    }
}

impl Five<String> {
    fn give() -> String {
        String::from("five")
    }
}

impl Five<f32> {
    fn give() -> f32 {
        5.0
    }
}

Then

println!("{}", Five::<i32>::give());
println!("{}", Five::<String>::give());
println!("{}", Five::<f32>::give());

Is it ever gonna be implemented in the language?

I don't know. It might be a good idea ot ask on internals.rust-lang.org, maybe it has been considered before but rejected for some reason. I could imagine type inference issues for example.