I keep seeing articles that demand the reader "Stop doing" something that is fine practice, if not good/best practices just because they saw some ...
For further actions, you may consider blocking this person and/or reporting abuse
Your first section heading,
Stop saying "Stop using Else" and other nonsense!
, would have been a better title. The first time I saw one of those (here on DEV) I thought what sort of "nonsense" is this before I even went into the post.done as requested
I found this page from c2 to explain it well, most articles on both sides misses the point. Early returns can be harmful, else can be harmful too - but it's situational and blaming the control structures rather than the surrounding code is irrational. Using decomposition and extraction like described in the link is a good solution, that we should focus on more instead. For more complex cases state machines, decision trees and even ML can be very useful.
wiki.c2.com/?ElseConsideredSmelly
Bonus: fun read on branching,
blog.cloudflare.com/branch-predictor/
no
else
can NEVER be "harmful", period ... stopped reading your comment when I saw that non-sense.So. This basically means you did not understand where the "don't use else" actually comes from. Else allows you to construct huge monsters of functions which you might want to break up. Just think about sequences of if/else or unreasonably nested ifs and elses. When you try to avoid else you're forced to split such a monster. So, else can be harmful, too. The point you're trying to make about being explicit is sort of true... but at least equally important is to be intentional.
if/else
chains are notelse
. They are chains ofif/else
that can be abused. Your argument is a strawman logical fallacy, you are trying to make the argument about somethingelse
entirely. (unavoidable pun, I spent 5 mins trying to avoid it :-)Your strawman can be shot down with one simple strawman. Guns do not kill people, people kill people. and thus Else does not make bad code, people make bad code.
Your complaint is a slippery slope logical fallacy as well, it is easily debunked by just do not do that. Jetbrains has code inspections and your slippery slope argument is one of the built in ones. You just turn it on at ERROR and your code will not compile without you manually marking it as ignore or dealing with it. This is a complete 100% chicken little non-issue.
You can abuse any language feature or construct to create atrocious spaghetti code. And one of those ways objectively is intentionally excluding
else
when there is anelse
clause. Just like excluding optional{}
on single lineif
orfor
statements. It is a best naive ignorance from misinformation and lack of experience or it is malicious hubris.The point is, excluding it when there is
else
logic that is just fall thru is a side effect programming, that introduces multiple classes of errors that are all invisible errors. Which is worse than someone naively writing some state machine that may become unwieldy.I have seen dozens of production errors in Fortune 500 and Fortune 50 companies that have cost millions of dollars a minute because of misguided dogma like
stop using else
. I have been the one that spent tens of hours searching for the issue, and yes there were tests, but the tests did not test for the side effects of unexpected data that triggered the issues that ranged from the app crashing to the app corrupting data so badly that backups had to be used in one case.Your entire stack of logic is flawed, it is an
if/else
morass of logical fallacies, the first of many is a strawman, it is easily debunked by the fact that you can just not do what you complain about. No need to enumerate the rest, that one is disqualifying enough.Exponential growth in cognitive load can never be harmful? Disagree. Exceptions can be harmful, loops can be harmful, even water can be harmful. Keyword "can".
that is a bunch of mumbo jumbo garbage, being explicit can never be anything but helpful. There is not a single actual instance that using an
else
block can be harmful, evenelse { // this block left intentionally blank }
is helpful, it explicitly informs the reader that there is noelse
condition. That removes the cognitive load from the reader, they no longer wonder if the code after theif
block is theelse
block implicitly that some noob intentionally omitted because of misinformation, misguided hubris and/or dunning/kruger effect.You've made good points, but for me personally being explicit will in certain cases just increase the cognitive load on me as a reader, and I'd prefer to not have it.
sincerely I would like to see an actual piece of code that is in software that is actually in use by a significant number of people or supporting a significant amount of money that would meet this criteria, that is NOT just bad code to begin with that could be remediated.
My 38 years of experience and the tens of millions of lines of code I have had to read that I did not write, some of which was 20+ years old, and had been touched by at least 100 different people over the 2 decades before me, I have never come across anything that meet your criteria. But I have seen plenty that forms my opinion on this.
I don't have any code off hand, but I've seen it in previous companies I've worked for. Experience or not, my personal opinion on the subject is that it increases my own cognitive load, and so I avoid that. It IS subjective after all.
it is not anymore subjective than gravity.
There are exceptions to literally everything. Gravity also is not set in stone anymore than mathematics is. That's still much less subjective than this though. This is very subjective. It is because my while you're pleading a very good case, it does not work for me. Therefore it is not objectively true.
Came for all the offended devs in the comments and was not disappointed.
Half the "tutorials" you see on YouTube and even numerous blogs are nonsense cash grabs. For example many if not most of those I am talking about also sell you a course that they swear will make you a full stack master in 72 hours if you'd only make the investment in yourself and purchase their 500$ to 5000$ course. Tons of concepts that are not actually beneficial get promoted on blog posts because the person making the blog is looking for content ... because content is money. There is a lot of "mocking bird" behavior in the tech circle. Hell, there are people that run blogs that haven't even had a dev job before -- they are just great at making content and their target audience never bothers asking too many questions. Its one thing if you are a hobbyist and present yourself as such. Its quite another to be giving interview advice when you've never had an interview in that sector. Its easy enough to spend a day watching YT videos and then just repeating what you heard there elsewhere. For that sweet ad sense money at the least as well as the hope of you buying their course. Rinse. Wash. Repeat.
Are they all like this? No. But there are plenty that are. Enough so that newer devs really should tread with caution because not all sources are quality sources. To put it bluntly: not everyone out there speaking actually knows what the hell their talking about. A lot of "the blind leading the blind".
The irony lol
But good article !
Great article
I actually talked about this in my article
Android's billion-dollar mistake(s)
Jean-Michel Fayard 🇫🇷🇩🇪🇬🇧🇪🇸🇨🇴 ・ Sep 25 '19 ・ 10 min read
You are totally right that there is not only one dollar billion mistake.
Tony Hoare, the creator of
null
, is not alone here. He stands out as a programming hero because he spoke out candidly about the fact that he made mistake. Which made it easier for people after that to realize that the mistake actually needed to be fixed instead of cargo-culting what previous languages did.Note that even after that people still don't understand what the mistake really was. I talked about it in this article
People understood that the
existence
of null itself is a mistake. Absolutely not.null
itself is fine,null
is a perfectly fine way to say that some data is not present in a list, a map, an API or something. Forcing people to useOption
or even worse "design patterns" (really: work-arounds) just makes the world worse.null
is not aBoolean
- Booleans have only two values damn it, that's in the very definition of a boolean - ,null
not aString
,null
not aRandomGenerator
, it's not anything of that.The argument was that allowing
null
to be a valid value of any arbitrary type is a mistake, because it means the compiler can't have your back. Once you fix that mistake,null
becomes your friend in languages like KotlinSee kotlinlang.org/docs/null-safety.html
Holy shit I'm gonna steal this as a mantra.
nope, and empty list, map or API return code can tell you that explicitly.
null
is implicitly ambiguous, and both of those things you should avoid at all costs, combined they enable apocalypse class of errors.concrete example;
I had to deal with this personally at work recently, upstream legacy data source has records peppered with
null
. Downstream they have been processed by multiple systems, before the report system gets the data. The report system has no idea why these fields may be null. Some of them are mandatory for the reports.Why are they null? Especially TIMESTAMP fields!
Are they null because null actually represents some specific state in the original system. Plenty of database fields that are
null
actually gets interpreted as0
or maybe-1
in some app somewhere probably both, how is a downstream system supposed to know that? Same with TIMESTAMP.No,
null
is a naive mistake that people keep making. Go made it withnil
.null
by any other name. They do not allow anything but references to benil
but like Shakespear said, "A rose by any other name...".The argument that a field like "LastEditTimestamp" should be
null
when the row has never been edited is the most common presentation. It is wrong as well.LastEditTimestamp
should initially beCreatedTimestamp
. There nonull
.Phone numbers that were never given can easily have "invalid" phone numbers like "1-555-555-5555" that have meaning to represent the missing information. Any person looking at this data will immediately recognize it as not a phone number and can question what it means. And a check for
null
and a check for this placeholder are the same amount of code. But one tells you something specific, the other is¯\_(ツ)_/¯
Missing reference that is a UUID, well there is a UUID for that NIL UUID
This goes on and on, in 38 years, every time someone just insists that
null
is the only solution, I have found a better one. Signpost values are the best solution to these cases.null
is never the best solution.Any system that has
null
in it should regard it as a hard error and stop the world, those systems are robust.We did this in the specific case at work and the number of issues with reports in downstream systems went to ZERO immediately. Now when there is bad data it never gets far enough downstream to break the reports, it has to be fixed before it can get that far and we know EXACTLY where in the pipeline the bad data either came from or was introduced.
Any language that disallows the concept of
null
ornil
or whatever excludes entire classes of bugs by default. Those languages usually disallow mutation as well, combined the number of classes of bugs that you have to deal with are reduced to something manageable and something you can reason about just by reading the code most of the time, because you do not have to keep huge state machines in your head.null
is bad in all cases.Hello,
Thanks for your response. I think that we in fact say complementary things, which is cool to reach a greater understanding.
So in my Kotlin codebase we have no issues using
null
, but we use it sparingly, probably 95+% of our fields are non nullable. And also 95+% of them are immutable. Non nullable and immutable is the default, and we deviate from it only when we know why.I would say that's relatively common to do so in the ecosystem, starting with the stdlib designed by JetBrains with pretty clear rules on when to use them or not.
I agree with many of your points:
The report system has no idea why these fields may be null
-> Also agre that it's important. And that's why we don't use null for reporting failures, they don't have enough information. Instead we use, not checked exceptions like in Java, because they are glorified GOTO statements, but anEither<Failure, Success>
type. An Either is a Monad but if the language supportstype X = Failure | Success
that's the same idea."Missing reference that is a UUID, well there is a UUID for that NIL UUID "
That's useful to know for langauges without null safety.
But for the others that mean you must remember to check manually every time:
if (uuid.isValid()) { ... } else { .. }
And who is more likely to never forget a safety check: a compiler or a normal human being?
Or what about this imaginary command line tool?
I'm sure you can find a more complex solution that works, but here I will apply your advice:
That would make my codebase worse so I feel safe to ignore the advice :P
If you're not already familiar with it, I think you'd enjoy the Elm programming language. It actually requires an
else
for everyif
because Elm evaluates everything as an expression, so theif
is really just a ternary operator with keywords.I ended up liking it so much I started using the ternary operator for everything in other languages. Most people would call it too terse (arguably failing the "explict > implicit" test in that sense) but to me it's worth it to have a syntax-level guarantee that I'm not creating subtle bugs like the ones you describe above.
Well... I wouldn't put it as strongly worded as you did, but I mostly agree I guess... Would rather summarize it as: "be careful with using guard clauses to obfuscate if/else logic." 😜
For everyone, the TL;DR: "Use If/Else, it's easier to read and understand when you do."
no, it is safer and less error prone when you do
The truth as always!