Publish boolean values post.

This commit is contained in:
Danila Fedorin 2020-08-21 23:06:26 -07:00
parent 6c3780d9ea
commit 06cbd93f05

View File

@ -1,7 +1,7 @@
--- ---
title: "How Many Values Does a Boolean Have?" title: "How Many Values Does a Boolean Have?"
date: 2020-08-20T18:37:50-07:00 date: 2020-08-21T23:05:55-07:00
draft: ["Java", "Haskell"] tags: ["Java", "Haskell", "C and C++"]
--- ---
A friend of mine recently had an interview for a software A friend of mine recently had an interview for a software
@ -38,12 +38,12 @@ in Haskell, and `1` and `0` in C. A boolean value is either true or false.
So, what's there to think about? There are a few things, _ackshually_. So, what's there to think about? There are a few things, _ackshually_.
Let's explore them, starting from the theoretical perspective. Let's explore them, starting from the theoretical perspective.
### What's a Type, Anyway? ### Types, Values, and Expressions
Boolean, or `bool`, is a type. Broadly speaking, a type Boolean, or `bool`, is a type. Broadly speaking, a type
is a property of _something_ that defines what the _something_ is a property of _something_ that defines what the _something_
means and what you can do with it. That _something_ can be means and what you can do with it. That _something_ can be
several things; for our purposes, it can either be an several things; for our purposes, it can either be an
_expression_ in a programming language (in the form of `fact(n)`) _expression_ in a programming language (like those in the form `fact(n)`)
or a value in that same programming language (like `5`). or a value in that same programming language (like `5`).
Dealing with values is rather simple. Most languages have finite numbers, Dealing with values is rather simple. Most languages have finite numbers,
@ -81,7 +81,7 @@ int meaningOfLife() {
No, wait, doesn't say "stack overflow" just yet. That's no fun. No, wait, doesn't say "stack overflow" just yet. That's no fun.
And anyway, this is technically a tail call, so maybe our And anyway, this is technically a tail call, so maybe our
C++ compiler can avoid growing the stack And indeed, C++ compiler can avoid growing the stack. And indeed,
flicking on the `-O2` flag in this [compiler explorer example](https://godbolt.org/z/9cv4nY), flicking on the `-O2` flag in this [compiler explorer example](https://godbolt.org/z/9cv4nY),
we can see that no stack growth is necessary: it's just we can see that no stack growth is necessary: it's just
an infinite loop. But `meaningOfLife` will never return a value. One could say an infinite loop. But `meaningOfLife` will never return a value. One could say
@ -131,7 +131,7 @@ It turns out to be convenient -- formally -- to treat the result of a diverging
as its own value. This value is usually called 'bottom', and written as \\(\\bot\\). as its own value. This value is usually called 'bottom', and written as \\(\\bot\\).
Since in most programming languages, you can write a nonterminating expression or Since in most programming languages, you can write a nonterminating expression or
function of any type, this 'bottom' is included in _all_ types. So in fact, the function of any type, this 'bottom' is included in _all_ types. So in fact, the
set of possible values for `unsigned int`: \\(\\bot, 0, 1, 2, ...\\) and so on. possible values of `unsigned int` are \\(\\bot, 0, 1, 2, ...\\) and so on.
As you may have by now guessed, the same is true for a boolean: we have \\(\\bot\\), `true`, and `false`. As you may have by now guessed, the same is true for a boolean: we have \\(\\bot\\), `true`, and `false`.
### Haskell and Bottom ### Haskell and Bottom
@ -173,7 +173,7 @@ They can then compile their program; the typechecker will find any mistakes
they've made so far, but, since the type of `undefined` can be _anything_, they've made so far, but, since the type of `undefined` can be _anything_,
that part of the program will be accepted without second thought. that part of the program will be accepted without second thought.
The language `Idris` extends this practice with the idea of typed holes, The language Idris extends this practice with the idea of typed holes,
where you can leave fragments of your program unwritten, and ask the where you can leave fragments of your program unwritten, and ask the
compiler what kind of _thing_ you need to write to fill that hole. compiler what kind of _thing_ you need to write to fill that hole.
@ -185,8 +185,8 @@ really count as a value, since it's just a nonterminating
expression. What you're doing is a kind of academic autofellatio. expression. What you're doing is a kind of academic autofellatio.
Alright, I can accept this criticism. Perhaps just calling a nonterminating Alright, I can accept this criticism. Perhaps just calling a nonterminating
function a value _is_ far-fetched (even though denotational semantics function a value _is_ far-fetched (even though in [denotational semantics](https://en.wikipedia.org/wiki/Denotational_semantics)
_do_ extend types with \\(\\bot\\)). But denotational semantics is not we _do_ extend types with \\(\\bot\\)). But denotational semantics are not
the only place where types are implicitly extend with an extra value; the only place where types are implicitly extend with an extra value;
let's look at Java. let's look at Java.
@ -195,13 +195,14 @@ core language level, any function or method that accepts a class can also take `
if `null` is not to that function or method's liking, it has to if `null` is not to that function or method's liking, it has to
explicitly check for it using `if(x == null)`. explicitly check for it using `if(x == null)`.
Java's booleans are not, at first glance, classes. Unlike classes, which you have This `null` value does not at first interact with booleans.
After all, Java's booleans are not classes. Unlike classes, which you have
to allocate using `new`, you can just throw around `true` and `false` as you see to allocate using `new`, you can just throw around `true` and `false` as you see
fit. Also unlike classes, you can't assign `null` to a boolean value. fit. Also unlike classes, you simply can't assign `null` to a boolean value.
The trouble is, the _generics_ part of Java, which allows you to write
The trouble is, the parts of Java dealing with _generics_, which allow you to write
polymorphic functions, can't handle 'primitives' like `bool`. If you want to have an `ArrayList` polymorphic functions, can't handle 'primitives' like `bool`. If you want to have an `ArrayList`
of something, that something _must_ be a class. of something, that something _must_ be a class.
But what if you really _do_ want an `ArrayList` of booleans? Java solves this problem by introducing But what if you really _do_ want an `ArrayList` of booleans? Java solves this problem by introducing
'boxed' booleans: they're primitives wrapped in a class, called `Boolean`. This class 'boxed' booleans: they're primitives wrapped in a class, called `Boolean`. This class
can then be used for generics. can then be used for generics.
@ -219,7 +220,7 @@ Boolean myFalse = false;
Boolean myBool = null; Boolean myBool = null;
``` ```
Beautiful, isn't it? And, unlike Haskell, where you can't _really_ Beautiful, isn't it? Better yet, unlike Haskell, where you can't _really_
check if your `Bool` is `undefined` (because you can't tell whether check if your `Bool` is `undefined` (because you can't tell whether
a non-terminating computation is as such), you can very easily a non-terminating computation is as such), you can very easily
check if your `Boolean` is `true`, `false`, or `null`: check if your `Boolean` is `true`, `false`, or `null`:
@ -249,17 +250,20 @@ while(test) test -= 1;
This loop will run 255 times, thereby demonstrating This loop will run 255 times, thereby demonstrating
that C has at least 255 values that can be used that C has at least 255 values that can be used
to represent the boolean `true`. There are other languages to represent the boolean `true`.
with the notion of 'truthy' and 'falsey' values. However,
some of them differ from C in that they also extend this notion There are other languages
to apply to equality. In JavaScript: with this notion of 'truthy' and 'falsey' values, in which
something not exactly `true` or `false` can be used as a condition. However,
some of them differ from C in that they also extend this idea
to equality. In JavaScript:
```JavaScript ```JavaScript
console.assert(true == 1) console.assert(true == 1)
console.assert(false == 0) console.assert(false == 0)
``` ```
Then, there are still exactly two distinct values Then, there are still exactly two distinct boolean values
modulo `==`. No such luck in C, though! We have 256 values that fit in `unsigned char`, modulo `==`. No such luck in C, though! We have 256 values that fit in `unsigned char`,
all of which are also distinct modulo `==`. Our boolean all of which are also distinct modulo `==`. Our boolean
variable can contain all of these values. And there is no variable can contain all of these values. And there is no
@ -269,7 +273,7 @@ respite to be found with `enum`s, either. We could try define:
enum bool { TRUE, FALSE }; enum bool { TRUE, FALSE };
``` ```
But unfortunately, all this does is define `bool` to be a numeric Unfortunately, all this does is define `bool` to be a numeric
type that can hold at least 2 distinct values, and define type that can hold at least 2 distinct values, and define
numeric constants `TRUE` and `FALSE`. So in fact, you can numeric constants `TRUE` and `FALSE`. So in fact, you can
_still_ write the following code: _still_ write the following code: