The Go
language creators write:
Go doesn't provide assertions. They are undeniably convenient, but our experience has been that programmers use them as a crutch to avoid thinking about proper error handling and reporting. Proper error handling means that servers continue operation after non-fatal errors instead of crashing. Proper error reporting means that errors are direct and to the point, saving the programmer from interpreting a large crash trace. Precise errors are particularly important when the programmer seeing the errors is not familiar with the code.
What is your opinion about this?
By that logic, breakpoints are evil too.
Asserts should be used as a debugging aid, and nothing else. "Evil" is when you try using them instead of error handling.
Asserts are there to help you, the programmer, detect and fix problems that must not exist and verify that your assumptions stay true.
They have nothing to do with error handling, but unfortunately, some programmers abuse them as such, and then declare them "evil".
assert
is being abused for error handling because it is less typing.So as language designers, they should rather see that proper error handling can be done with even lesser typing. Excluding assert because your exception mechanism is verbose is not the solution. Oh wait, Go doesn't have exceptions either. Too bad :)
I dislike asserts intensely. I would not go as far as saying they are evil though.
Basically an assert will do the same thing as an unchecked exception would, the only exception is that the assert (normally) should not be kept for the final product.
If you build a safety net for yourself while debugging and building the system why would you deny this safety net for your customer, or your support help desk, or anyone that will get to use the software that you are currently building. Use exceptions exclusively for both asserts and exceptional situations. By creating an appropriate exception hierarchy you will be able to discern very quickly one from the other. Except this time the assert remains in place and can provide valuable information in case of failure that would otherwise be lost.
So I fully understand the creators of Go by removing asserts altogether and forcing programmers to use exceptions to handle the situation. There is a simple explanation for this, exception are just a better mechanism for the job why stick with the archaic asserts?
I've recently started adding some asserts to my code, and this is how I've been doing it:
I mentally divide my code into boundary code and internal code. Boundary code is code that handles user input, reads files, and gets data from the network. In this code, I request input in a loop that only exits when input is valid (in the case of interactive user input), or throw exceptions in the case of unrecoverable file / network corrupt data.
Internal code is everything else. For instance, a function that sets a variable in my class might be defined as
and a function that gets input from a network might read as such:
This gives me two layers of checks. Anything where the data is determined at run-time always gets an exception or immediate error handling. However, that extra check in
Class::f
with theassert
statement means that if some internal code ever callsClass::f
, I still have a sanity check. My internal code might not pass a valid argument (because I may have calculatedvalue
from some complex series of functions), so I like having the assertion in the setting function to document that regardless of who is calling the function,value
must not be greater than or equal toend
.This seems to fit into what I'm reading in a few places, that assertions should be impossible to violate in a well-functioning program, while exceptions should be for exceptional and erroneous cases that are still possible. Because in theory I'm validating all input, it should not be possible for my assertion to be triggered. If it is, my program is wrong.
I admit having used asserts while not considering proper error reporting. However, that doesn't take away that they are very helpful when used correctly.
They are especially useful for if you want to follow the "Crash Early" principle. For example suppose you're implementing a reference counting mechanism. At certain locations in your code you know that the refcount should be zero or one. And also suppose that if the refcount is wrong the program won't crash immediately but during the next message loop at which point it will be difficult to find out why things went wrong. An assert would have been helpful in detecting the error closer to its origin.
assert
is very useful and can save you a lot of backtracking when unexpected errors occur by halting the program at the very first signs of trouble.On the other hand, it is very easy to abuse
assert
.The proper, correct version would be something like:
So... in the long run... in the big picture... I must agree that
assert
can be abused. I do it all the time.