Do you remember the post I made about Truthy and Falsy back in December? How I said I understood it? What a sweet, naive child I was. It’s not like anything was wrong with that post, it’s just that there is so much more.
Here’s a little more of that iceberg.
A few months back, when I was learning Clojure, I came across some interesting information in the docs. Apparently when Clojure computes an &&
or an ||
statement, it doesn’t return true
or false
, it returns one of the values in the statement. So it could be returning a string, or a number or a list or nil. So it could return true
or false
too if that is one of the values. It kind of blew my mind. But it shouldn’t have.
One thing that languages that use the concept of “truthy” can do is take “boolean operators” like and
and or
and just, not return booleans. What it does for and
s is that the language will return the first false if it’s false and the last true if it’s true. For or
it returns the first true if it’s true or the last false if it’s false. It makes sense when you break it down because it returns the last statement that it needs to evaluate. A lot of the time you can just ignore the fact that it returns these things. After all, if you extract the conditional into its own function, the value it returns is still going to have the truthy value you expect even if it’s a string or an array.
Now, for some reason, I took this as a cool Clojure thing and moved on with my life until I ran across it in TypeScript. Now since TypeScript is a statically typed JavaScript (give or take), it does a lot of what JS does. I hadn’t realized that JS did the same thing* with its boolean operators. I realized this when I tried to pull a lengthy conditional into its own named function for clarity and TypeScript yelled at me becaues the return values couldn’t be converted to a boolean.
Here’s a simpler example in TypeScript with react. We’re seeing if a prop is there at all, and then the length of that prop
atLeastOneResponse = (): boolean => (
(this.props.form.responses && this.props.form.responses.length)
)
The thing is, that’s going to start yelling. this.props.form.responses
can either be an array of strings or undefined, while both of those things can be falsy, neither can be false. And this.props.form.responses.length
can be a number (which can be falsy if it’s 0 or truthy otherwise) but it can’t ever be true or false. And the code says it returns a boolean so it’s sad that none of those returns are actually booleans. To fix it, we can use the double bang.
atLeastOneResponse = (): boolean => (
!!(this.props.form.responses && this.props.form.responses.length)
)
The one thing about boolean operators in these circumstances, at least as I’ve seen so far is that while an and
or an or
doesn’t have to return a boolean, not
seems to always return a boolean. I can’t wait until I encounter a language where that’s not the case () but in the mean time, I’ll count on ![truthy value] to be false and a ![falsy value] to be true. Therefore !![truthy value] is going to be the boolean true. :tada:
But wait there’s more!
Here’s why I feel especially dense. I’ve known for about a year that you could do assignments like this in Ruby: value = hash[:key] || "default”
where if there’s no :key
key in hash
it’ll assign your variable value
it to the default. It was one of those fun facts that I just knew worked and didn’t think too hard about until I wrote it backwards by accident and realized the same “first truthy or last falsy” applied here too. It’s also why it’s “dangerous” to use it when the value of your key could potentially be false
because that would be evaluated the same as the nil
(aka falsy) it would return if there were no key that matched.
This means that kind of assignment can work in any language that follows this pattern. Whether or not it’s idiomatic or a bad idea for other reasons is still worth thinking about, but it’s always nice to know it’s an option. It’s also always nice to know why things work.
*Truthy in JavaScript is a party. And by party, I mean it has no coherent rules. Empty objects and arrays are truthy but an empty string is falsy. ¯\_(ツ)_/¯