Requiring all language constructs be expressions and eliminating statements means that you avoid a lot of duplicate effort in the language design.
For example, in C-like language you have if-else statements and ternary expressions. The ternary expression does "the same thing": as condition statements, but it also evaluates to a value. So in functional programming languages, you just have the one kind of conditional expression, and then maybe some syntactic sugar to morph it into more ergonomic forms.
You can do clever stuff with it, for example `HashMap<string, ()>` is practically identical to `HashSet<string>` (depending on how clever the compiler is, possibly actually identical).
Really a unit type is just one that contains only a single value. This is a unit in the same way that 1 is a unit for the integers. With some hand waving it is an identity for product types, for example (int, ()) is the "same" (xxxmorphic yada yada) as int
As a 0-tuple, it becomes a specific case of a more general concept -- there is some beauty/usefulness in not having to have a "special" construct for "Unit", which is (in a sense) not just "any" unit type. It also "justifies" the syntax of `()` and notes that it is a product type, all the while fitting into the idea of the "cardinality" of `(a1, a2, ..., an)` being the product of the cardinalities of each of its type params.
Some other options could be to use None (like Python does) or Nil or Nothing itself, or even ReturnsNothing to be more explicit, or even the Pascal-style procedure keyword, instead of the function keyword, for a sub routine that returns nothing.
But seriously, according to that link, it seems to me like the zero or empty type is more suitable.
But I am not a PL or type theory expert.
That's a bit different. The empty type is only suitable for functions that never return (e.g. loop infinitely, crash the program). The type checker will prevent functions that have the empty type as a return type from returning.
The confusion is probably because "empty" can mean two things:
- What's inside the returned value. That may be why the parent suggested empty for the unit type. But that's now what "unit" means in the common parlance.
- How many possible values can be returned. Never returning means the function has zero possible return values.
In Elm (a functional language for making web UIs), you might use the unit type for a lazy view function. If and only if some condition is true, call a view function to render some stuff into your DOM tree as in the function viewIfLazy [0]. There's only one way to call that view function, so let's call it with the unit type.
Now, what about using the Never type (a type with no members that can be instantiated at runtime [1]) to do accessibility? In Elm, your DOM elements have type `Html msg` where msg is a type _parameter_ for your actual message type that makes your app update itself. Usually you create that type like `type Message = UpdatedTheFooCounter Int | UpdatedTheNameInput String | ClickedTheBlahButton` something like that. Then the type on your inputs and buttons will be `Html Message` (read as "Html of Message" or even "Html parameterized by Message").
Well, it's bad a11y practice to have onclick events attached to divs and spans and things that aren't buttons, generally. So you can give your divs type `Html Never` and then if you try to attach an onclick event to them, you find that you can't at compile time, because the members of the type Message are not members of the type `Never`. tesk9/accessible-html is a package that enforces that [2] (I kind of simplified how it does that because I'm deep enough in the weeds already).
[0] https://github.com/elm-community/html-extra/blob/0b8fc70752c...
[1] https://package.elm-lang.org/packages/elm/core/latest/Basics... also has a simpler example now that I think of it.
[2] https://github.com/tesk9/accessible-html/blob/master/src/Acc...