diff --git a/content/blog/boolean_values.md b/content/blog/boolean_values.md index 5db645c..6a48219 100644 --- a/content/blog/boolean_values.md +++ b/content/blog/boolean_values.md @@ -1,7 +1,7 @@ --- title: "How Many Values Does a Boolean Have?" -date: 2020-08-20T18:37:50-07:00 -draft: ["Java", "Haskell"] +date: 2020-08-21T23:05:55-07:00 +tags: ["Java", "Haskell", "C and C++"] --- 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_. 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 is a property of _something_ that defines what the _something_ means and what you can do with it. That _something_ can be 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`). 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. 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), 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 @@ -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\\). 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 -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`. ### 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_, 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 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. Alright, I can accept this criticism. Perhaps just calling a nonterminating -function a value _is_ far-fetched (even though denotational semantics -_do_ extend types with \\(\\bot\\)). But denotational semantics is not +function a value _is_ far-fetched (even though in [denotational semantics](https://en.wikipedia.org/wiki/Denotational_semantics) +we _do_ extend types with \\(\\bot\\)). But denotational semantics are not the only place where types are implicitly extend with an extra value; 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 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 -fit. Also unlike classes, you can't assign `null` to a boolean value. -The trouble is, the _generics_ part of Java, which allows you to write +fit. Also unlike classes, you simply can't assign `null` to a boolean value. + +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` 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 'boxed' booleans: they're primitives wrapped in a class, called `Boolean`. This class can then be used for generics. @@ -219,7 +220,7 @@ Boolean myFalse = false; 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 a non-terminating computation is as such), you can very easily 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 that C has at least 255 values that can be used -to represent the boolean `true`. There are other languages -with the notion of 'truthy' and 'falsey' values. However, -some of them differ from C in that they also extend this notion -to apply to equality. In JavaScript: +to represent the boolean `true`. + +There are other languages +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 console.assert(true == 1) 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`, all of which are also distinct modulo `==`. Our boolean 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 }; ``` -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 numeric constants `TRUE` and `FALSE`. So in fact, you can _still_ write the following code: