5 ms·
How to assert for fun and profit (2022)
- gleenn 3y agoI use assert, but I feel like effort writing assertions in production code could be spent writing any and/or more thorough automated tests. Even if the tests are slow, you won't affect production speed. You usually can test far more in depths than verifying things inline in functions. You also wouldn't have the problem the OP mentions about not realizing that Intellij was by default not running with assertions enabled which could easily be dangerous. Just write real tests!
- pacaro 3y agoI don't see this as either or. Good quality asserts can be very effective when managing objects with complex state transitions For me assertions are for invariants. The code has no expectation of successful execution I also like (borrowing from testing) the idea of expects, where we can hope that the object is in a specific state, but have an explicit compensation path for when it isn't, perhaps objects that need to be migrated to a new schema etc.
- usefulcat 3y agoInline assertions do have one big advantage over tests: context. They're right there in the very place where the condition must hold. For that reason, I have long thought of assertions as 'comments with teeth'. Also, inline assertions can be enabled any time, not just when running unit tests. Of course in theory that last bit shouldn't make any difference, but then I'm sure you've already heard the old joke about the difference between theory and practice..
- lelanthran 3y ago> I'm sure you've already heard the old joke about the difference between theory and practice.. It's not a joke, it's a fact of life that we learn soon after graduating, and then relearn again, and again, and ...
- Buttons840 3y agoAsserts are essentially checked comments and an automated test is not a replacement for comments. I've done things like the following many times: if (x != 5) { ... 40 lines here ... } else { assert(x == 5); ... more lines ... } The main purpose of the assert is to remind the reader that x == 5. There was a time where I would use a regular comment for a reminder like this, but since it's something the computer can check, I mine as well turn my regular comment into a checked comment.
- kccqzy 3y agoThe danger is change. What if someone comes and then due to a new business requirement changes the code to if (x != 5 && x != 6) { ... 40 lines here ... } else { assert(x == 5); ... more lines ... } Because of the 40 intervening lines the person might never see your assertion! If you work in a project with automated tests that do not have sufficient coverage, this is just a spectacular way of blowing up production. Assertions are bad because they are checked at runtime which is too late. The ideal checked comment should have the checks happen at compile time. Something like Liquid Haskell.
- Terr_ 3y ago> blowing up production. I prefer what Java does: Assertions are disabled at runtime by default, however you can turn them on without requiring a different code-release and you can even do it for specific packages/classes. So you might even use them in production: If feature X is already failing in some bizarrely uninformative way, turning on assertions in relevant code may provide you a better hint to what's going awry.
- spc476 3y agoThen the assert() triggers and you fix the assert() (or the bug). What's the issue here?
- kr0bat 3y agoIn this example the assert is less explanatory than a comment. Why do if (condition): ... else: assert(!condition) ... When you could instead if (condition): ... else: #if (condition) ... Or otherwise explicitly comment the condition that was checked earlier. At least then if the comment is unchanged, whoever is touching your code will assume the comment is outdated, rather than assuming that you're asserting that x should be some undocumented magic number.
- indigoabstract 3y agoUnit tests are complementary to assertions, they don't supersede them. I feel that assertions are the first line of defense against programming judgement errors/omissions and are much easier to write in the given context than unit tests.
- diogenes4 3y ago> effort writing assertions in production code Presumably the assert is used because it doesn't consume resources (ie effort) to write. Testing takes a lot of effort.
- 0xDEAFBEAD 3y agoSeems to me that asserts are a force multiplier on tests. If you have a bunch of asserts, every test case you write is extra valuable -- you aren't just verifying correct input/output behavior, you're also verifying that all asserts held. In the extreme case, I can imagine ditching all your small-scale unit tests for a combination of asserts and end-to-end integration tests.
- flohofwoe 3y agoIn C and C++ at least, asserts are also hints for the static analyzer (for instance that a pointer isn't expected to be null). It's better to do both, asserts and tests are not mutually exclusive, they complement each other.
- aiunboxed 3y agoThis has always been a debate in my head whether to make the function return error codes or to throw those errors. Irrespective of throwing an error or returning an error you need to handle it somewhere. If you are returning an error then the type system can handle it and the person calling your function can get an idea.. while if you are throwing an error in most of the languages your caller function will not get an idea that this function can throw an error.
- happytoexplain 3y ago>if you are throwing an error in most of the languages your caller function will not get an idea that this function can throw an error Is this true any more? I feel like most languages, relative to popularity, have compiler-enforced thrown error handling.
- gdprrrr 3y agoC# is one of the offenders. And while Java has checked exceptions, many considered Thema an annoyance and wrap everything in RuntimeException.
- flakes 3y agoVery true. Checked exceptions in Java are a form of function coloring problem for modern libraries. Especially painful when using any of the functional style stream operations, like `map`, `filter`, etc, or any other higher order function library. Most take in the standard `Function` or `BiFunction` interface arguments, which will not support method referencing for anything which includes a checked exception as part of its signature.
- gpderetta 3y agoBut a better language would allow generalizing over exceptions. In pseudo C++: auto map(collection<T> C collection, function<T> F f) -> invoke_result<F, T> throws(invoke_exception<F, T>);
- 3y ago
- jackblemming 3y ago>I wouldn’t blame you for invoking Objects.requireNotNull on your arguments, but think about whether that’s better than an assertion for the end user. My position is that it’s not, since the user would be seeing precisely the same exception, manifesting in exactly the same way. Note that it’s not wrong to use both, as assertions can be far more powerful. Is this true if the function forwards the value to another function, which may do the same thing?
- ggm 3y ago> The pronunciation of assert This section I like very much. I wish Haskell people had the balls to do this for the X -> x -> x sentences and a myriad of other Haskellisms. I still pronounce assert(x) as "If you see the message, then the condition it asserts has FAILED"
- deleted 3y ago[deleted]
- kr0bat 3y agoHonestly, my first question was "why not use a combination of user-created types and exceptions to ensure program validity." But I get the impression that asserts are used for alerting programmers to their own syntactical and logical errors; unlike exceptions, which can occur in logically proper code.
- diarrhea 3y agoExactly. Assertions are for programmers and their internal work. Exceptions for the rest, mainly the dynamic, user controlled inputs and their derivatives.
- doubloon 3y agoi dont understand why i as a user would want a program to assert (i.e. crash) in an interactive program. i would lose all my in-progress work and have to start the program over from scratch. and chances are very low i will be able to report the bug to the programmer, for various reasons. so the programmer will never know about it. i will just keep having to restart the program over and over and workaround it. i get that its better than memory corruption. but ... is it better than just muddling through and reporting you cannot do operation x?
- ok_dad 3y agoThis would probably be used in places where, if the “x” in assert(x) doesn’t hold, then the program could do more harm than good. You’ll generally try to handle situations that are recoverable without blowing up stuff like this, but in some software and some situations you want it to blow up fast rather than destroy data or whatever. I program in Python more, which has slightly different assert behavior so it’s considered more of a code smell in that language, but it seems like Java programmers use it more because it can be turned off easily when not wanted.
- flohofwoe 3y agoAsserts are not an alternative to validating user input or input data in general (e.g. data loaded from files or received over the network). If wrong input triggers an assert, that means that the input validation is incomplete (and in that case the assert may prevent further much worse damage, and also provide important information to the programmer who's going to fix that bug). Basically, asserts should never trigger if the user "does something wrong".
- thfuran 3y agoThe user obviously doesn't want the program to crash, but they don't want to encounter any bugs. If an assertion fails, it means they already encountered a bug and the program is about to wander through a minefield of unspecified behavior, which could be much worse than simply stopping.
- 0xDEAFBEAD 3y ago>Assertions MUST NOT be the only thing between misbehavior and input data, including data returned from other APIs (e.g. fopen calls, i.e. auto x = fopen ("foo"); assert (foo != NULL); is invalid). Anything dealing with foreign data must not assume anything about the state or contents of the data, and as such, cannot ever assert, as it doesn’t have an assertion to make. If you take away only one thing from this article, let it be this: assertions do not verify arbitrary inputs. The author seems overconfident in this point. Like, what if the "input data" is from another software system I control? Triggering an assert failure on bad user input is a little sloppy, but if there's no way to recover at that point anyways, I don't see why it matters. Can someone enlighten me?
- brickers 3y agoRe: data from another of your own systems. If there’s an interface between them that suggests you probably want those systems decoupled. Maybe in the future you replace one system with another you don’t control - ideally it would be nice not to have to make code changes because of that. Re: asserting on user input. If you assert only then what happens on bad inputs when asserts are switched off in prod? Seems like an outcome you’d like to control at the time rather than allow to propagate (by writing bad data to a db and only being discovered months later, for example).
- 0xDEAFBEAD 3y ago>what happens on bad inputs when asserts are switched off in prod Good point
- Arech 3y agoIt'd be nice if the author mentioned the real purpose of assertion statements: *it's meant to catch a programmers' errors (your own, or other people working with your code). Not a users' errors.* From that stems all assert use-cases and all requirements to it.
- Arech 3y agoand from that - all the reasons to use it. A properly placed assertion statement is the only thing that stays between you and a misery of weeks-long debugging sessions.
- Omroth 3y ago"Assertions MUST NOT be the only thing between misbehavior and input data" I don't agree with this. I'm quite happy to assert that an external function call worked.