Today I learned that in Rust


#1

Today I learned that in Rust if you have any type and a function of the same name, they are imported and/or reexported as a unit, you can use both.


mod module {
    #[derive(Debug)]
    pub struct Recipes {
        v: Vec<String>,
    }
    
    #[allow(non_snake_case)]
    pub fn Recipes<'a, I>(iter: I) -> Recipes
        where I: IntoIterator<Item=&'a str>
    {
        Recipes {
            v: iter.into_iter().map(String::from).collect()
        }
    }
}

pub mod prelude {
    pub use module::Recipes;
}

use prelude::Recipes;

fn main() {
    let r: Recipes = Recipes(["Carrot Cake & Jam", "Tuna Salad"].iter().cloned());
    println!("{:?}", r);
}

Playground link

It’s kind of an oddity. Quiz time: Why?


#2

Not only you have learned it today! :slight_smile:


#3

Here is a real world example from the rustc: https://github.com/rust-lang/rust/blob/ff713464e6530fab2e13d0965929d8189c59ae56/src/libsyntax/ptr.rs#L48-L58


#4

Also, whenever you write a tuple struct, you get this implicity.
struct Foo(i32) creates both a type Foo and a constructor Foo: fn(i32) -> Foo.


#5

Relevant thread from the internals: https://internals.rust-lang.org/t/rust-type-values-namespace-status/3734


#6

I saw today that rustc uses this by using FnvHashSet as both a type alias and a function. So rust’s own internals are using it (I guess the compiler hackers would be the ones to know these corner cases).


#7

Personally I really dislike this pattern because it is very surprising to me, but I think if it were made more normal by documenting it, using it in the standard library, and so on, I would feel more okay with it. Right now I’m much more comfortable using associated functions as constructors.


#8

I was incredulous, so I agree with you.

It’s tempting to use it, now that I know it exists! However, I see that rustdoc does not emit any docs for such a punned function.


#9

New day, new learn: The X macro pattern, in Rust!

From alexcrichton we learn how you can use “X macros” neatly in Rust. The idea is that you define list of things in one macro, and make it take another macro’s name as a parameter.


#10

Yep, it’s also used in Cargo here: https://github.com/rust-lang/cargo/blob/ebcf0a8f41759717876bca5871137ab48e06f790/src/bin/cargo.rs#L74 (and breaks IntelliJ Rust resolve inside the subcommand modules :frowning: )