Why is bool syntactically different from other enums?

This is more a language design question. I think booleans are just enums with two variants: true and false. But in the rust language, the syntax for handling bool is quite different from handling other enums like Option and Result. What was the reason for this design? Perhaps someone could point me to an RFC that has the discussions surrounding this.

ok I just realized that technically nearly all the Rust primitive datatypes are enums. Like i32 is something with bunch of variants. I guess then I'm just looking for a guiding principle for deciding when a datatype should be primitive and when it should be enum.

Ah I just realized that bool is special in that it works with if. No other enums work with if. For other enums you're supposed to use match.

hrm.. what then is the point of the system of {bool, if} when {enum, match} can do the same? Is there something special about {bool, if`}?

bool isn't an enum; true and false aren't variants. E.g. try this:

let _ = bool::false;
let _ = bool::r#true;

Those are values. But maybe you'd like to read up on the pattern types concept. Lots of links here, though I didn't check thoroughly to see if there's a better citation.

For bool's syntax specifically, programmer expectation and language precedent. E.g. people are use to and expect if/else blocks, true and false, etc.

Some related discussions around an ASCII enum vs u7-esque, should variants be exposed, etc.

3 Likes

Here’s an early proposal from 2014: Represent equivalent `enum`s the same as `bool`, make `bool` an `enum` by glaebhoerl · Pull Request #330 · rust-lang/rfcs · GitHub

Most pre-1.0 discussions of this basically seem to conclude with “we could do this, but it doesn’t really seem necessary.”

7 Likes

Just that people expect it to be there. There's no technical reason to need if in the language at all.

(TBH, it's bad syntax, and something like cond would be way better, but humans like what they're already used to.)

1 Like

I wonder who was the one that pushed for Rust to mimicry under C++-alike language.

I would argue that objectively current syntax of Rust is, in many aspects, worse then what early versions of Rust had, yet it resembles typical curly-braced C++-wannabe closely enough that lots of people become hooked before they realize it's not, really, a C++ clone.

That was probably as important to make it accepted as mainstream language as deep innovative ideas hidden behind that somewhat ugly syntax.

Yeah, I'm not saying that it was the wrong choice for Rust. Just that it's not objectively-good syntax.

Rust being "O'Caml in C's clothing" has definitely been good for it.

2 Likes

As someone with an interest in PLs I'm genuinely curious: What's not objectively-good about it?

Well, first is the general Boolean Blindness | Existential Type problem with anything special-casing bool.

But moreso it's the lack of an overall grouping for the construct, and the corresponding awkwardness of else if and the inconsistent alignment for conditions and such.

See https://docs.racket-lang.org/reference/if.html#(form._((lib._racket%2Fprivate%2Fletstx-scheme..rkt)._cond)) for an example of how Racket does it.

Rather than

if C0 {
    BLOCK0
} else if C1 {
    BLOCK1
} else {
    ELSEBLOCK
}

if I tried to make a rusty version kinda like match, maybe it'd be something like

if {
    C0 => BLOCK0,
    C1 => BLOCK1,
    else => ELSEBLOCK,
}

which would also helps reduce the requests for a :? as it'd be more terse, and wouldn't result in so many "can I just remove the braces for else return?" kinds of things, since like with match you don't need braces for single-expression things.

3 Likes

Arguably it's a bit noisy, especially when used with a single expression in the body. Also, the use of keywords for something as fundamental as a conditional jump might seem odd if it wasn't so widespread.

Look at Haskell's pattern guards for a more elegant conditional syntax.

The ergonomics of treating boolean logical values (classically "true" and "false") specially are, in the eyes of a lot of language designers, worth the cognitive overhead of treating boolean as an exceptional type. It is, ultimately, an aesthetic and design choice, rather than a formal one.

As you note, Rust-without-bool isn't that different from Rust as it exists today. I would propose, however, that it'd be incrementally harder to onboard developers coming from other languages, as a result, and potentially also harder to teach people the language.

Alternately, one could consider Rust-but-with-enumerated-bool:

pub enum Boolean {
  False,
  True,
}

and redefine operations like == to evaluate to this type. That's orthogonal, certainly, in so far as Boolean then becomes structurally similar to any other two-valued enumeration, but it doesn't add anything beyond that that I can see.

ok I just realized that technically nearly all the Rust primitive datatypes are enums

Only in so far as the set of values is both finite and closed. There is a qualitative difference between even a small integer type (u8, say) and most enums - specifically, the integer types have far more values than an enum would be expected to.

You certainly could define

enum UnsignedEight {
  U0,
  U1,
  // … and so on …
  U255,
}

and define corresponding operations. You can do that today - in fact, Rust allows the compiler to store such an enum in a u8-sized piece of memory, even. The ergonomics are terrible because enums were never designed to accommodate this kind of use - try defining "add" on top of this enum and you'll likely see why.

1 Like

Graydon has mentioned on mastodon that one of his goals for Rust was to provide a safety raft for C++ developers, so the answer may well be "the guy who designed the original language."

Rust has come a long ways from being Graydon's pet project (he hasn't been involved in any meaningful capacity in years, for example), but I don't think there has been any movement to actively reject or repudiate that goal, even if it's no longer a priority. Being accessible to people coming from a C++-like background is, at some level, baked into the language.

To be clear, that is not a bad thing, and Rust today stands on its own merits, and not on the merits a C++ programmer might appreciate. Being accessible to existing programmers has a bunch of useful social features, and Rust achieved something I think is special in introducing some more modern language ideas to that audience.

4 Likes

Note that I consider the type pretty unimportant here.

We could have #[lang = "bool"] #[repr(u8)] pub enum bool { false, true } in the standard library somewhere, with pub use whatever::bool; pub use whatever::bool::{false, true}; in the prelude, and I don't think any user of rust would care.

It's really just the if syntax that's special for it. The type is boring.

3 Likes

No, that's not true. Original language used sigils and looked pretty alien to C++ developers.

Not as alien as Hakell or Lisp, but alien enough.

Also, Graydon wrote explicitly: the syntax is, really, about the last concern and I wonder who exactly was passionate about syntax to develop that C++ disguise that worked so well (even if I still hate it a tiny bit, I admit that it was quite efficient for what it was designed for).

Someone else pushed for a reform to remove all these sigils, to adopt angle brackets (and turbofish to resolve grmmar ambiguity), replace ret with return and so on.

And that happened long after Graydon left the project.

I imagine that if one really wanted to know, they could find it in the git repos somewhere in the period up to and including 2015, when a wild Rust 1.0 appeared.

any no_std or no_implicit_prelude crates would break. that's a pretty big deal.

This isn’t quite accurate. For example, angle brackets were introduced before Rust 0.1, and ret changed to return in Rust 0.4. Both of those happened while Graydon was still leading language development.

2 Likes

core is still part of the standard library, and lang items bind standard library types for the compiler, so this new enum would be what the bool keyword resolves to, so strictly there's nothing blocking this. It just seems a bit useless.

2 Likes

true and false are keywords, but not bool (nor other primitive type names).

Huh. You learn something... around about once every two weeks.

1 Like