Publish boolean values post.
This commit is contained in:
parent
6c3780d9ea
commit
06cbd93f05
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user