Rationale about not impl Display for unit type ()

I didn't find any rationale about why we didn't have a Display implementation of unit. I run into this cause in some generic API I impl a trait for () that represent "Ignore Error" so the type of Error is (), I mandate all Error impl Display but so () is not Display. That not a problem, I just declared that Error associate type of () is something else. But that raise my curiosity about Display and unit. I search in reddit ,issues, forum, stack overflow, duckduckgo, google, everywhere I could I found no talk about it.

Some found:

I don't known if it would be a good thing to implement Display, first unit is not universal, there is no obvious way to represent it outside of Rust, however that also mean Rust could choice how unit should be display. It's nice for generic.

"unit" versus "()" I guess. What do you think, could we add it, is it a good thing ?

One relevant aspect of Display is that it comes with an automatic to_string method. I don't quite see how to_string feel all that appropriate on (); but of course feel free to disagree :slight_smile:

5 Likes

How do you print a () to the user? Most likely empty string, but I don't think this is applicable to all cases.

1 Like

For better or for worse, for the situation you described I've been using my own Never type (since one is not yet stabilized in std as I recall)

To me, this encodes the uninhabited nature of an error that does not occur (so may fit your idea of an error that is always, by definition, ignored)

enum Never {}
impl Display for Never {
    fn fmt(&self, _: &mut fmt::Formatter) -> fmt::Result {
        match *self {}
    }
}

Playground

2 Likes

Side note: std::convert::Infallible

4 Likes

I think that’s a sufficient reason not to implement Display for (): because it’s impossible to present the value of the unit type to the user without falling into nerdview.

8 Likes

And consider in particular the use case of an error value. (() also doesn't implement std::error::Error, but let's ignore that). What should the text be even in that case?

It can't be the empty string, because then programs would print messages like

Error:

which aren't very friendly. It could be something like “no further information is available”, but then the standard library is making a specific arbitrary choice of wording that might not make sense for other applications.

As I see it, Display should be implemented for types which have a single obvious choice of string representation. ("Obvious" in that there can be others; for example, numbers can be printed in many bases but the world has standardized on base 10.) () does not have such a single choice; the correct representation of it is context-dependent.

7 Likes

The solution for your problem is that, rather than using an empty tuple (), to create your own zero-sized error type

pub struct SomethingIsWrong;

impl Display for SomethingIsWrong { ... }

You avoid the issues with (), get a clear name for the error type, and can implement Display however you want. You can also declare many different error types for different error cases, and no one needs to guess "what did () as an error stand for?".

Just as, most of the time, you should prefer explicit structs with explicit field names instead of nameless tuples, you should prefer custom zero-sized structs to (). The primary reason to use () is as a special case of the more general n-ary tuples. This is common inside of macros, or when doing type-level programming.

9 Likes