Imagining a Language Without Booleans
Posted3 months agoActive3 months ago
justinpombrio.netTechstory
calmpositive
Debate
60/100
Programming LanguagesBoolean LogicLanguage Design
Key topics
Programming Languages
Boolean Logic
Language Design
The article explores an alternative programming paradigm without booleans, using optional values instead, sparking a discussion on language design and the role of booleans in programming.
Snapshot generated from the HN discussion
Discussion Activity
Very active discussionFirst comment
19h
Peak period
53
12-24h
Avg / period
12.2
Comment distribution73 data points
Loading chart...
Based on 73 loaded comments
Key moments
- 01Story posted
Sep 22, 2025 at 6:09 PM EDT
3 months ago
Step 01 - 02First comment
Sep 23, 2025 at 1:17 PM EDT
19h after posting
Step 02 - 03Peak activity
53 comments in 12-24h
Hottest window of the conversation
Step 03 - 04Latest activity
Sep 27, 2025 at 3:40 AM EDT
3 months ago
Step 04
Generating AI Summary...
Analyzing up to 500 comments to identify key contributors and discussion patterns
ID: 45340215Type: storyLast synced: 11/20/2025, 2:30:18 PM
Want the full context?
Jump to the original sources
Read the primary article or dive into the live Hacker News thread when you're ready.
This looks homeomorphic to the Maybe monad.
homeo implies continuity
Struggling to imagine it? Don't worry. John H Conway has done it for you.
https://en.wikipedia.org/wiki/FRACTRAN
The value is 6 is a:true, b:true, c: false, d: false, etc..
I love fractran tho, I must have written a thousand lines of it this year alone.
2025, we can all just use integers and carry one less variable type in our sack.
Next we replace integers with floats and we’re done. 3 birds, 1 stone.
I highly doubt that. Let's call a boolean that is represented as one bit "true boolean type" Since no instruction set (that i'm aware of) has boolean operators, a "true boolean" would require every operation on it to evaluate to multiple bit-wise operations, which take up registers and cycles. Flags in registers are "true boolean", but they're usually operated on explicitly like int with bit-wise operators.
There is also the issue of bit alignment, atomic access, and stack and heap allocations being byte based; further restricting how a language that had "true booleans" would be able to actually be able to work with them.
I know that there are some languages that allow boolean arrays to be packed tightly as "true boolean", but that is a rare exception. Even char and byte types has this issue sometimes, but are more commonly "properly packed".
> we can all just use integers
So it's all integers already. The most common implementation of boolean around is probably #define true 1
But we really should use enums more instead of boolean. "fail, success, bad_param, error_404" is equally efficient to return as a bool.
> Next we replace integers with floats.
No. (well python and JavaScript kinda does already, but no) https://en.wikipedia.org/wiki/Pentium_FDIV_bug
- NARS2000 dialect of APL, Ball / Interval arithmetic: https://wiki.nars2000.org/index.php/Ball_Arithmetic
There's a robot controller that I work with that has a large number of calibration tables, of float32 values. This is where I store the json! :D
> Let me know if you’ve seen anything more similar.
If you take static typing off the table, then Icon's goal-directed execution is very much an inspiration in this area.
[1]: https://journal.stuffwithstuff.com/2023/01/03/type-checking-...
We ideally want an infix function that can reduce the "truthiness" of two values.
Let us imagine this language is a Haskell-type-thing, and we can define pseudo-operators with pattern matching
Hmm, let's see how that looks The good news is that we are free from the tyranny of booleans. The bad news is that we just reinvented JavaScript :-)https://en.m.wikipedia.org/wiki/Elvis_operator
?:-)
Good Job! Now do the "no scalar values" challenge. FP fanbois gonna love the unwrapping.
There's a whole lot more to JavaScript typing that makes it JavaScript.
After all, Python does this too (but the spellings are "and" and "or").
The first one has some arbitrariness (do you take the left or right value if both are Just). But, thankfully the Applicative typeclass gives both <* and *>, which lets you choose which value you want:
(There's the possibility to merge values too, with f <$> Just A <*> Just B, which evaluates to Just (f A B). I feel like this is a "don't try to understand it, just get used to it" sort of syntax. It can be pretty convenient though.)` if (node.last_child(s) is Ok(last_child))`
Is the part between the () not ultimately the same as a boolean expression? Like he wrote his own implementation of if/else syntax?
Also in the beginning he says: "An if with an else can produce a value", but isn't this just 'syntactic sugar'? I think the code that actually runs is the same as if you'd write if (value x = some_value) {value = something} else {value = something_else} ?
I still don't get what's the use of this, or is this just a curiosity? It seems like the result is just a kind of ternary operator? Doesn't this still just compile to if(x.present) return x else y? Just with really obtuse syntax
There would be no branching if there were no "if". It's basic assembly. Not jumps. No loops.
It isn't going to matter that it's technically a "JSON::false" or whatever... you're still going to get people calling that a wart forever. ("But a JSON::false would be a None" - no, you need that for either "null" or "missing". A JSON library has to have an exposed "false" value to distinguish it from null and missing, both for input and output.)
I'm not saying that doesn't mean to try this out, but as more of a heads up and something to talk about explicitly in the eventual tutorial.
Personally, I find myself fairly satisfied with if statements rigidly requiring a boolean and refusing to have a concept of "truthiness", which I consider a mistake, and I'm not sure this is solving real problems I've had. A user can always write the Option vs. None themselves in an if statement with mandatory else if they want. This introduces a wrapper level of Option that may not always play nice in real code (I mean, a lot of sum type types essentially already have it built in with things like "type Color = Red | Blue | Green | Unspecified" where adjoining a None is often unnecessary) and may really tempt you towards a concept of truthiness that may be a bigger wart than when you're trying to fix. It's pretty hard for a computer programming language to essentially evict the concept of a "bit" from the language. I'm not sure it can be done in practice, but it's fun to think about it and I encourage the pondering.
But is
different from ? Is it a type-level construct to express a predicate like ?In any case, optional types containing boolean values are definitively an anti-pattern.
And in cases where it's prudent to check for the "presence" of a property containing a
, while using coercion, it does not make sense to distinguish false from "falsy".TypeScript's dynamic narrowing has become pretty comprehensive when it comes to this kind of issue.
Still, Option<Boolean> types are bad in most contexts I think, especially in languages like JS.
Instead of using boolean | undefined , I much prefer explicit defaults (parameters) or properties being declared every time (data).
A mask array is just a bunch of boolean, and follows boolean math, because it is boolean values. A boolean type does not make a boolean value, it being two state does.
Everything old is new again.
Yes. we can get a Lisp background to get a better rounded and wiser perspective on all these topics.
(Also 0 == true in Ruby. Only false or nil are not true.)
[1]: https://wiki.haskell.org/Logic_programming_example
It's a bit weird to me that the result `not` discards the content of the value rather than just swapping its truthiness (not A?E : E?A).
> The closest thing I’ve seen is fallible expressions in Verse, but those are pretty different because they (i) don’t assign a value to an if without an else, and (ii) involve speculative execution.
Traditional ifs, and the ifs here, also involve speculative execution :) (i.e. execution that happens regardless of which branch you end up on). It's just delimited by the brackets of the if condition (a ‘failure context’ in Verseland). It's true that traditionally logic languages don't assign a value to failure. I guess algebraic effects (of which `Result` can be an example) can be seen as a generalization of failure in that way.
Amr Sabry &a. also have an interesting notion of ‘failure with value’ as the semantics of their negative types: https://dl.acm.org/doi/abs/10.1145/3434290 , http://lambda-the-ultimate.org/node/4964 (LtU for an older paper from the programme).
Icon and Verse use failure (backtracking!) as false and all values as true, but you still have conditionals and boolean logic even though you don't (or may not) have a boolean type.