Jörg W Mittag gives an excellent answer. But I think it does miss the heart of the question. The quote says "For the sake of this discussion, let's call the bottom type a type that has no members." So while Jorg is right that the "the defining feature of a bottom type is not that it has no members" and that "it is perfectly possible for a bottom type to have members", we should also consider that it is perfectly possible for a bottom type to have no members.
Why would a type with no members be useful and why can't we just use the unit type for the same thing?
Unit and None
So let's consider a language that has a type
Unit with one member
unit and a type
None with no members. I'll assume that unit is not a member of "ordinary" types like
Int. While we are at it, let's assume that the only members of
Int are integers.
A case for
If we declare a function
fun foo() : T is .... end
where T is a type, that usually means that if a call returns, it returns a value that is a member of type T. Or to put it another way
Any call to foo either returns a member of T or doesn't return
If T is Unit, that means that any call to foo will return (if it returns) a member of Unit, i.e. unit. Since the value returned is entirely predictable, there is no point writing say
val x : Unit = foo()
since the value of x is a forgone conclusion. We might as well just write
Unit is playing the role that void plays in C or Java. The only difference is that we are treating Unit as a type, whereas in C and Java void is not really a type.
So what about None, why not use that instead of Unit for our analog of void?
fun bar() : None is ... end
From our understanding of what this means, we see that
Any call to bar either returns a member of None or doesn't return
But since None has no members, this is equivalent to
No call to bar returns.
That doesn't sound like void.
None is not a suitable analog for void, but
Three cases for
Is there any point to having
Here are three arguments for having a
None type. But note that these arguments don't really rest on
None having no members, but rather that it is a subtype of all other types in the language, i.e. that it is a bottom type.
None as a return type
A function that returns
None sounds pretty useless. But it isn't completely useless. Suppose I have a function that always throws an exception, then I can write
fun unreachable() : None is
throw new AssertionError("Unreacble code reached")
This can be useful for defensive programming. E.g.
fun partial(a : Int) : Int is
if a > 0
else if a < 0
This should type-check since None is a subtype of Int.
What if we had used used Unit for the return type of
unreachable? The subroutine above would not type check. Since Unit is not a subtype of Int). So we'd have to rewrite the else part as, for example
which looks rather arbitrary.
Here is a more compelling example. Here we have a generic function
fun assertWithResult<T>( b : Bool, v : T, m : String := "Assertion failed" ) : T is
return (throw new AssertionError( m ) )
For this to typecheck, we need for
throw new AssertionError( m ) to have the bottom type. If we rewrite the code as
throw new AssertionError( m )
The language implementation will (I'd hope) complain about the missing
return. We can't rewrite it as
throw new AssertionError( m )
since there is nothing we can write in the place of ....
null is not the answer because I'm supposing
null is not a member of
Int, for example. unit has the same problem. I'll consider the case where there is a null value that's in every type later.
None as the type of something that isn't there.
Suppose our language has lists. (These are lists of values, as in Haskell -- not lists of locations as in Python.)
A reasonable rule for list catenation is that the type of
xs ++ ys is
List[T|U] where the type of
xs is List[T], the type of
T|U is the smallest type that contains the union of the members of
What is the type of the empty list constant
. If it is
[1,2,3] ++  will have type
List[Int|Unit], which is probably not what you want. But if the type of the empty list constant is
List[None] we have
List[Int|None] which is
Let's introduce multiple inheritance into our language. Given two interfaces
J we can write
I&J for the combination of both. I.e. the members or
I&J are exactly the members of
I intersected with the members of
J. Why not allow intersection types for any two types? Now what is
None comes to the rescue.
Error without Unit or None
In Haskell, there is bottom type that has one member, which represents an error value. This error value is also a member of all other types.
The arguments above don't require that the bottom type have no members, just that it is a bottom type. (This is the point Jörg made.)
Imagine a language where we have a bottom type
Error that contains one value, call it
err that represents an error; and where
err is a member of all types.
err is the value of expressions that have errors, e.g., the value of
1/0 might be
err and the value of
1/0 = 1/0 would also be
err. (In the literature
err is often written $\bot$ and called "bottom", but I'm going to avoid that terminology so that the term bottom isn't used with two technical meanings.) It follows that
None is not a type in this language. (Int and Unit are also ruled out, but let's define a new type
Int? that contains only integers and
err.) We'll say that a function that does not return a value implicitly returns
err. For example
fun incr( x : in out Int?) : Error is x := x+1 end
is a reasonable function. (The implementation won't complain about a missing return, because
return err is implicit.) It always returns
err but, if we don't use the value, this is not an issue.
fun baz() : Int?
var y : Int? := 0
This will type-check since
Error is a subtype of
Int?. Personally, I'd rather that it not type-check. I'd rather find out about the error before run time. So even if my bottom type contains an error value, I'd still like to have a unit type (
Unit?) that additionally contains a non-error value. My personal feelings aside, this is a possible language design.
We can do without None by making the value of
In short, whether or not you have an error value that is a member of every type or not, is largely orthogonal to the other issues such as whether you want
Unit. But it makes a difference to whether your bottom type is empty or not.
Error better than
One argument for all types having an error value holds for languages with lazyness. Suppose we have a type Int*Int that consist of pairs of Integers. In a lazy language
(i, a[i]) (where
i is an integer variable and
a is a list of integers) must have a value, even if
i is an out of bounds index. That's because
first( (i, a[i] ) would have no error at compile or run time. But no pair of integers makes sense if
i is out of bounds. The solution is to have
Int? instead of
Int. (You could have both, but the type of
a[i] or any integer expression that might contain an error should be
A very pragmatic reason to have an error value is for uninitialized locations in an imperative language. Again you could have both
Int, but locations of type
Int would have to be initialized to integer. This is sort of the approach Java takes. Locations of type
int are initialized to 0 by default. But location of type
Integer are initialized to
null by default. Granted,
null is not the same as
null is a first class value.
There are theoretical reasons for all type having to be inhibited by an error value. For example in Dana Scott's domain theory all types have a bottom value and this is important for showing that all well-typed functions have a meaning.
Finally, we might consider a design where every type (except
Error) has some particular non-error value, call it "null". Think of Java with the primitive types int, bool, double, etc. expunged. Now we can have a type
Null that contains only
null. (Or, if all inhabited types should have an err value, we can have a type Null? that contains only
null and err.) I don't think there is much of a case for a
Unit? type containing both
null. Do we still need
None? I think none of my arguments above for
None are strong in this case. We can ditch the
None type and then
Error if you have
err as value and
Error as type) will be the bottom type and also the stand in for void.
Summary of types mentioned above
None no members, subtype of everything
Error contains only
Null contains only
Null? contains only null and err.
Unit contains only
Unit? contains only
Int contains only integers.
Int? contains only integers and
List[None] contains only the empty list.
List[Int] contains only lists all of whose members are integers. Supertype of
T | U the smallest type that contains all members of
T and all members of
T & U a type containing only values that are members of both