Personally I'm not much of a fan of assert()'s... at least in the language I use the most (C++). It's not that I don't think you should validate the input ranges of parameters to functions its that in general exceptions are better.
Assert(): A Modern How To
21–30 of 33 posts
Re: Assert(): A Modern How To
#22An overlapping technique (covering some but not all of the circumstances you'd use assert) is to take a parse-dont-validate approach, and essentially encode the fact that an assertion has been applied to a value in its type. How ergonomic this is will vary by language, but the general idea would be to apply the assertion logic in some sort of constructor, then prevent any operations which would break the invariant go…
It is so nice to come here and want to say something, and someone already said it. For those who haven't read "Parse, Don't Validate": https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-va... I'm not sure exactly what languages people think of when they consider asserting, but I presume it's Java, C# or C/C++. In Java asserts are disabled by default, so they're thought of as a debug/development utility. In ano…
Re: Assert(): A Modern How To
#23> Can assertions be used in production? Yes > What should I be asserting on? Invariants > Can I customize how assert behaves? It should abort the program, logging the stack and whatever the context you pass into in, printf-style. If it doesn't abort, it just buries the issue of the program being in incorrect internal state. It should never be OK.
Additionally recommended: if attached to a debugger, the program should stop in the debugger, immediately, without printing a message (you can look at the code), or getting a stack trace (the debugger can do that), or whatever else, to avoid possibly triggering further asserts or causing more problems. This leaves the state just as it was (or as near as feasible), so that it can be investigated. After being stopped i…
Since the above is a well-known technique, it has now been generalized and standardized via "std::breakpoint" in C++26 - https://en.cppreference.com/cpp/utility/breakpoint
This function standardizes many similar existing facilities: __builtin_debugtrap from LLVM, DebugBreak() from Win32 API, __debugbreak Microsoft Specific C/C++ extension, debugger_break from boost.test, assert(false), _asm { int 3 } (MSVC) and asm("int3") (GCC/clang) for x86 targets, etc.
Re: Assert(): A Modern How To
#24Personally I'm not much of a fan of assert()'s... at least in the language I use the most (C++). It's not that I don't think you should validate the input ranges of parameters to functions its that in general exceptions are better.
The article gets things flatly wrong from its first, ah, assertion. Asserts aren't for validation: the condition is supposed to be impossible to be false, just not provable by the type system. If invalid input can come through normal operation of the program, you use a normal runtime check, not an assert.
Very nicely said!
Re: Assert(): A Modern How To
#25If we're trying to outline a future for assertions, I think it would help to situate them among the other mechanisms we have for ensuring correctness and explain where assertions have the right tradeoffs. For example, what unique need does a production assertion API satisfy that a normal conditional throw does not? Are there cases where production assertions are still necessary even when invariants are established th…
See https://news.ycombinator.com/item?id=49231133 An "assert" is for "impossible to fail" conditions while "throw" is for conditions which might fail within the valid state space of the program.
> Are there cases where production assertions are still necessary even when invariants are established through type constructors?
Yes. Even though there is an equivalence between "Predicates Types" (Curry-Howard correspondence) many languages do not have a robust type system to avail of this (eg. C). In the "Axiomatic" approach to "Programming Language Semantics" a language construct's (eg. if/switch/while etc.) specification is given by "precondition and postcondition" which are asserts that must hold before and after the construct. This is the famous "Hoare Triple" and later extended by Dijkstra in his wp-calculus and demonstrated in his "Guarded Command Language". The same idea holds when the code between precondition and postcondition is a function/class/module/etc. in which case it is called a "Contract" for that piece of code.
Re: Assert(): A Modern How To
#26 ok( conditional, message );
https://testanything.org/Re: Assert(): A Modern How To
#27Interesting article about a worthy topic, even though I disagree with some it. Side note: I expected to see mention of design by contract and function preconditions/invariants/postconditions. I don't think the article is well founded. Before you can discuss usage you need to establish the semantics for assert(). The author touches on this in the introduction but then leaves the details unexamined. In particular I'd n…
> Side note: I expected to see mention of design by contract and function preconditions/invariants/postconditions. For some reason, DbC seems to be virtually unknown to most programmers. It's incredibly strange: I was sure that DbC would be the next big step after gradual typing. It's just such a natural fit: where the type system gives up (any/dynamic), the contract system can step in. There are papers on automatica…
Re: Assert(): A Modern How To
#28There's a whole big contentious point that the author completely ignored: using assertions in tests (like unit-tests). Some unit testing frameworks expect their users to use assertions to do the job, others are very much against it because they want to separate between the failures of the system under test from failures of the test. (If that matters, I'm in the later camp). * * * I also think that the article confuse…
> Some unit testing frameworks expect their users to use assertions to do the job, others are very much against it because they want to separate between the failures of the system under test from failures of the test. (If that matters, I'm in the later camp). How useful is this distinction in practice? A failing test is going to examined in detail and that examination is going to reveal whether the system under test…
Imagine working in a larger company, where you routinely get close to a hundred of useless emails every day. Imagine they use some garbage mail server like the one provided by Office 365, so that filtering is broken, emails get lost all the time etc. And now your CI is sending you alerts about code breakage, and you need to... wait, not just scroll through an endless Jenkins log, you need to download, unzip the artifacts, figure out which files are the test logs, and from there try to figure out what the test was doing and whether the error has anything to do with your code.
This whole process is infuriatingly unnecessary, tedious, it contributes nothing to whatever goals you've set for yourself. It's a toil that you have to engage in every day, perhaps for hours, just to come back with the answer "looks like it's not my problem after all".
I know this because I've been on the receiving end of this anger and frustration :) And I've never found a good way to eliminate this problem completely, but I'm sure that narrowing down the number of people the problem is reported to only to the most relevant people helps.
Re: Assert(): A Modern How To
#29Earlier quoted context omitted.
> Side note: I expected to see mention of design by contract and function preconditions/invariants/postconditions. For some reason, DbC seems to be virtually unknown to most programmers. It's incredibly strange: I was sure that DbC would be the next big step after gradual typing. It's just such a natural fit: where the type system gives up (any/dynamic), the contract system can step in. There are papers on automatica…
Can you share the links to all the papers that you refer to?
- Matthias Felleisen, Sam Tobin-Hochstadt, “Interlanguage Migration: From Scripts to Programs” (DLS 2006)
- Sam Tobin-Hochstadt, Matthias Felleisen, “The Design and Implementation of Typed Scheme” (POPL 2008)
- Sam Tobin-Hochstadt, “Typed Scheme: From Scripts to Programs” (2010).
- Asumu Takikawa et al., “Gradual Typing for First-Class Classes” (OOPSLA 2012)
- Esteban Allende, Johan Fabry, Éric Tanter, “Cast Insertion Strategies for Gradually-Typed Objects” (DLS 2013)
- Esteban Allende, Johan Fabry, Ronald Garcia, Éric Tanter, “Confined Gradual Typing” (OOPSLA 2014).
- Nadia Polikarpova, Ilinca Ciupa, Bertrand Meyer, “A Comparative Study of Programmer-Written and Automatically Inferred Contracts” (ISSTA 2009).
There's a lot more research and literature on the topic. Naive approaches were tried ~2010 and were shown to be performance disasters, but by ~2015 we already had those issues mostly solved. I seriously thought that every new language (or new release of an existing PL) after that would feature first-class support for contracts and gradual typing, along with built-in support for automatically generating/harvesting types and contracts from tests. It's 2026, and the mainstream still doesn't seem aware of the possibilities, much less actively going in that direction. It's nuts!
Re: Assert(): A Modern How To
#30Earlier quoted context omitted.
It is so nice to come here and want to say something, and someone already said it. For those who haven't read "Parse, Don't Validate": https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-va... I'm not sure exactly what languages people think of when they consider asserting, but I presume it's Java, C# or C/C++. In Java asserts are disabled by default, so they're thought of as a debug/development utility. In ano…
Some of the newer Java features are really nice for this: sealed interfaces, records, sealed interfaces, and record pattern matching
I would say the killer features are records and pattern matching.
Sealed interfaces/classes seem to mostly compensate for hypermobility caused by inheritance (that you can modify a superclass'es behavior and break abstraction boundaries).
Stop relying on inheritance, and you don't really need sealed interfaces.
Using records and thus lowering mutable state makes the problem of breaking abstraction boundaries lesser as well.
This is a hot take paid for by the functional programming lobby.