DEV Community

Discussion on: Code Smell 24 - Boolean Coercions

 
netch80 profile image
Valentin Nechayev

So you still provide some border between values which are implicitly treated as false, and those as true, but your border is so only "void" and "false" are false. What about "undef", "null", etc., whatever they are named in different languages?

Empty data structures are empty, but that doesn't mean they don't exist.

But they are empty. Just no data. If this is, for example, a list, you have no values in it => nothing to process.
Why don't you consider boolean checking here as a handy manner to check its state?

Thread Thread
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️

I guess what it comes down to is that an empty array holds no data, while a nil-value itself represents no data. When a value appears in an if statement, only the value itself should be considered, not its actual contents. Otherwise, what about an array like [[], nil, {key: undefined}]? This doesn't hold any value either, as all of its values are, themselves, "empty". But there's still some structure that holds information.

There's also the question of identity; does [] == [] return true? In JavaScript it doesn't, so the language clearly considers two "empty" arrays two distinct values, so it makes sense to me that they'd be considered something rather than nothing in an if statement as well.

But most importantly, I think both if (nil) { unreachable } and if (0) { unreachable } continue, in some way, the idea from languages like C that a null-pointer, representing a pointer to nothing, when put in an if statement, evaluate to false so the if statement doubles as an if exists construct; but in modern languages, nil-values and numeric zero values are two distinct things, so it is possible to continue to treat nil-values as falsey without continuing to do so for numeric zero values too.

Another example would be linked lists: when your variable stores a pointer to the head of the list, and the last element points to null as its "next" pointer, then it makes sense that an empty linked list is a null-poiner, and indistinguishable from a non-value other than by its type. In a functional language with a proper type system, sure, but not in C, that would have been a really bad idea. But again, in more modern languages, we can more easily distinguish an empty collection from no collection at all, so it makes less sense to treat the former as a falsey value.


Sorry for the slightly disorganised thoughts, but I barely just had my morning coffee and can't really be bothered to write a full article on a topic that, at the end of the day, still comes down to what seems more reasonable on a subjective level.

Thread Thread
 
netch80 profile image
Valentin Nechayev

Sorry for the slightly disorganised thoughts

Really nothing to ask sorry, because all this raises tons of basic problems. You slightly touched here, for example, meaning of "null": is it "asserted nothing" or "unknown"? In Javascript, it is first. In SQL and floating (as NaN), it is second. But in SQL it is, in practice, typically used as first, and this discrepancy causes tons of subtle bugs. Your comparison of [] == [] is from the same terrain: comparison by sense and comparison by reference - they shall be clearly different. Lots of other similar cases.

But what I try to predicate here is that, despite these problems are eternal (and, definitely, any who studies IT shall eventually get acquainted with them, the earlier the better), there could be come shortcuts, convenient for most typical cases. And, in this sense, all examples could be reconsidered. I'm not familiar in practice with Javascript (only a tiny chunks of glue anything), my fields of experience are Python (closest to the discussion origin), C/C++, Java, slightly - SQL. And, from POV closer to all them:

Otherwise, what about an array like [[], nil, {key: undefined}]? This doesn't hold any value either, as all of its values are, themselves, "empty".

As said above, yes, it holds a value. (Hmm: with Ukrainian/Russian rules I'd have to write "No, it holds a value".) If you have difference between undefined and nil, then undefined is "don't know" and nil is "definitely nothing". The latter is already a piece of data. Well, your example really could be rewritten as e.g. [undefined, undefined] - it's closer to what to consider.

Python currently converts any non-empty list (tuple) to true. If the rules changed to "if any list element is true, the whole list is true; otherwise, false", it could be accepted. Instead, they used the simplest approach.

does [] == [] return true? In JavaScript it doesn't

Well, this is heavy Javascript insanity, along with all other its peculiar like weird result of []+{}. There shall be explicit univocative manners to compare contents and to compare references. In Python, for example, first is "==" (overriddable if needed) and second is "is" (not overriddable). That's clear. In Javascript, both "==" and "===" are specific. It's hard and complely unhandy.

then it makes sense that an empty linked list is a null-poiner, and indistinguishable from a non-value other than by its type.

This is how LISP works: () is the same as nil and treated as false. Well, LISP is the oldest and definitely not strongly typed functional language :)

and can't really be bothered to write a full article on a topic that

For just me, no need. Well, this is public discussion and somebody other could get interested, but, in this case, 1) we have already provided enough examples to start delving into, 2) this should be rather a separate article than just a comment, and properly prepared.
As already said I understand the whole (I hope;)) complexity of the issue. But people still try to make handy cases easier, and provide a policy how boolean check is performed on different data types. No variant is ideal, but some are definitely better than others, some are really clueless. We need to avoid all clueless rules and keep ones that looks generally not bad:)

Thread Thread
 
mcsee profile image
Maxi Contieri

The whole problem here is null

So, avoiding "the billion dollar mistake", we don't need all of the above stuff.

Sounds easy. It is easy

Thread Thread
 
netch80 profile image
Valentin Nechayev

Sounds easy. It is easy

"For every complex problem there is an answer that is clear, simple, and wrong." (c)
This is exactly the case you show here.

Thread Thread
 
mcsee profile image
Maxi Contieri

Ok. I respect your opinion

Thread Thread
 
netch80 profile image
Valentin Nechayev

I respect your opinion

Thanks:))
I'd add that Hoare is too self-blaming. At the moment he devised NULL, it was good solution. As always, remedy renders into poison only in excessive amounts. What we really needed is strict non-NULL guarantee at compiler level - and, well, this is what is added to much part of newer languages and tools; and, where we are sure any NULL is not allowed, this shall be marked, to allow checking. For God's sake, developer tools are now powerful enough.
The more problem I've faced once is that the whole set of "undefined" and "null" is not enough in some cases. This was a monitoring tool where we had to invent multiple cases as "sensor is absent", "sensor is unreachable" and "sensor is failing". This doesn't fit into traditional approaches with a single special value, but a language which allows algebraic types nicely fit here. Over recent ones, nearly any do (with different efficiency).