Self constructor works with unit struct but not with ()

Is this a bug? At least the behavior feels odd to me.

struct Unit;

pub trait Tr {
    fn foo() -> Self;
}

impl Tr for Unit {
    fn foo() -> Self {
        Self // works
    }
}

impl Tr for () {
    fn foo() -> Self {
        Self // fails
    }
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error: the `Self` constructor can only be used with tuple or unit structs
  --> src/lib.rs:15:9
   |
15 |         Self // fails
   |         ^^^^

error: could not compile `playground` due to previous error

struct Unit; introduces a const (https://rust-lang.github.io/rfcs/1506-adt-kinds.html#unit-structs), but there's no const for () for Self to find.

Can you say why you want this to work? After all, () is special in lots of ways, like how it works to just

impl Tr for () {
    fn foo() -> Self {}
}
2 Likes

I stumbled upon it, when implementing mmtkvdb::storable::Storable for other unit structs than () and wanted to keep the implementations following the same schema in all cases.

I guess someone could stumble upon it when using macros. (Update: Something like this Playground, though I see it can be easily worked around.)

I don't really need this to work, but I found it curious.


To phrase it differently: I believe if Self is a valid constructor for unit structs, then it should also be a valid constructor for the unit struct, i.e. for ().

1 Like

() is not the unit struct. It's not even a unit struct. It's not even a struct, because it's a tuple. It's not a UDT but a built-in type that happens to be unit because it's the product of 0 other types. Since it's not a UDT, its constructor is not named but derives from the constructor syntax for tuples.

3 Likes

Oh, I made a mistake. It's indeed not called the unit struct but the unit type. (see reference)

For convenience and historical reasons, the tuple type with no fields (()) is often called unit or the unit type. Its one value is also called unit or the unit value.

So agreed, it's not a struct, but it's still unit. :grin:


Anyway, I see the pattern now. Basically Self as constructor isn't allowed because it's unit but because Self replaces the name.

struct U();

pub trait Tr {
    fn foo() -> Self;
}

impl Tr for U {
    fn foo() -> Self {
        Self()
    }
}

impl Tr for () {
    fn foo() -> Self {
        ()
    }
}

(Playground)

I guess it makes sense then how it is.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.