Enum variants and newtype as functions/closures?

I was surprised to find out this syntax even allowed.

So, this works -

assert_eq!(Ok::<_, ()>(9).map(Some), Ok(Some(9)));

And this one works as well -

#[derive(PartialEq)]
struct Foo(u8);

assert_eq!(Ok::<_, ()>(9).map(Foo), Ok(Foo(9)));

So, newtypes and enum variants with payload are acting like functions? I mean I can pass them as a closure to, say, map().
Is this documented? Any pointers?

1 Like

Yes.

Unit structs, newtypes and tuple structs all live simultaneously in both the type/module namespace and the value/function namespace. Only standard, braced structs live exclusively in the type/module namespace.

struct Unit; // exists as a value
struct Unit2(); // exists in value namespace as a 0-arg function
struct Newtype(u8); // exists in value namespace as a 1-arg function
struct Tuple(u8, u8); // exists in value namespace as a 2-arg function
struct Regular { value: u8 }

// fn Unit() {} // the name `Unit` is defined multiple times
// fn Unit2() {} // the name `Unit2` is defined multiple times
// fn Newtype() {} // the name `Newtype` is defined multiple times
// fn Tuple() {} // the name `Tuple` is defined multiple times
fn Regular() {} // ok

This is also related to why you cannot write Self(x) to construct a newtype, while you are allowed to write Self { value: x }. (because Self is a type and not a value, or something like that).

3 Likes

Thanks for the explanation! Any pointers to the relevant documentation? I want to be able to teach this in the best possible way

1 Like

I suspect it isn't written. Without a complete language reference, the way I usually answer tricky questions like this for myself is to just throw snippets at the compiler, and see how it fits against my mental model.

In the WIP Rust language reference, I even see something that seems odd to me:

A tuple struct expression consists of the path of a struct item, followed by a parenthesized list of one or more comma-separated expressions (in other words, the path of a struct item followed by a tuple expression). The struct item must be a tuple struct item.

The reason I call this odd is because I do not know of any way in which tuple struct expressions actually differ from a simple function call, so it seems unusual to me that the reference even recognizes them as a distinct concept.

Thanks to @scottmcm for this link posted in another thread, which seems relevant here:

https://github.com/rust-lang/rfcs/pull/1506

1 Like

Many thanks for the help!