6 ms·
The behavior of 'assert' is not an anomaly. It comes from 'design by contract.' Assert is primarily meant to be documentation of constraints in code and seconda
by michaelfeathers 10y ago
The behavior of 'assert' is not an anomaly. It comes from 'design by contract.' Assert is primarily meant to be documentation of constraints in code and secondarily a way of catching errors during development.
"Contract conditions should never be violated during execution of a bug-free program. Contracts are therefore typically only checked in debug mode during software development. Later at release, the contract checks are disabled to maximize performance." - https://en.wikipedia.org/wiki/Design_by_contract https://en.wikipedia.org/wiki/Design_by_contract
- blowski 10y agoIt's not an anomaly, but it can be a surprise for people who don't understand what it does. For example, they use asserts for validation and then the validation doesn't work in production. It's absolutely right the way it works, but it's still a gotcha for the audience this blog post is aimed at.
- coldtea 10y ago>It's not an anomaly, but it can be a surprise for people who don't understand what it does. That's almost a tautology though.
- blowski 10y agoThe point is that they think they understand it, because most of Python behaves the same in development and production. You see this function called 'assert', it gives the right error at the right time, and all is good. Then you push it to production and it stops throwing errors. Eventually, you read the manual and it tells you that this specific function is ignored in production. This is a surprise because, say, print doesn't behave like that.
- coldtea 10y agoThat only happens if you have different production and development environment settings though -- in which case you should expect the different results. In this particular case, you compiled your code with "-O", so it's not the "same code" used in production, but code compiled with a different flag. Shouldn't they check what the flag does?
- blowski 10y agoThe developer may be deploying code to a server they didn't configure. I agree with the way it's done in Python, as it's consistent with most other languages. But the blog post is right to point out to inexperienced developers that the way assert behaves might give them a surprise.
- michaelfeathers 10y ago> but it's still a gotcha for the audience this blog post is aimed at. Would be nice if they had a pointer to the reason, however.
- sangnoir 10y agoUnless the article was updated after your comment: the reason is right there in the article: "However, Python does not produce any instructions for assert statements when compiling source code into optimized byte code (e.g. python -O). That silently removes whatever protection against malformed data that the programmer wired into their code leaving the application open to attacks. The root cause of this weakness is that the assert mechanism is designed purely for testing purposes, as is done in C++. Programmers must use other means for ensuring data consistency."
- sitkack 10y agoI would argue that one should never use '-O' it also strips doc strings from running code. Not really an `optimization` but they had do something right? One couldn't run __unoptimized__ in production could they?
- HerrMonnezza 10y ago> I would argue that one should never use '-O' it also strips doc strings from running code. Python `-OO` strips docstrings, `-O` basically only disables assertions. See: http://stackoverflow.com/a/4777156/459543 http://stackoverflow.com/a/4777156/459543
- vram22 10y ago>See: http://stackoverflow.com/a/4777156/459543 http://stackoverflow.com/a/4777156/459543 Or just do "python -h": -O : optimize generated bytecode slightly; also PYTHONOPTIMIZE=x -OO : remove doc-strings in addition to the -O optimizations Same on both Py 2 and 3.
- 10y ago
- catnaroek 10y ago> Assert is primarily meant to be documentation of constraints in code Real or imagined constraints? AFAICT, an assert only tells me what you wish your program did, but that has absolutely no bearing on what it will actually do.
- coldtea 10y agoNeither "real" nor "imagined". An asserts checks DESIRED constraints. >AFAICT, an assert only tells me what you wish your program did, but that has absolutely no bearing on what it will actually do. Depending on the implementation, an assert can either merely log or absolutely stop a program that doesn't pass its test, so it very much has a bearing on what the program will actually do.
- catnaroek 10y ago> An asserts checks DESIRED constraints. Then imagined it is. Your desires are totally a part of your imagination, unless you make them become real. > Depending on the implementation, an assert can either merely log or absolutely stop a program that doesn't pass its test, so it very much has a bearing on what the program will actually do. Point taken. Unfortunately, logging errors or aborting the program won't make assertions magically become true, though.
- JonnieCache 10y agoIf you have the process quit it definitely stops them from being false though. I thought that was the point of assert()?
- catnaroek 10y ago> If you have the process quit it definitely stops them from being false though. The assertion remains false for the final process state, before the process quits. Outside of the process, the assertion is simply meaningless (neither true nor false), because the assertion's free variables are only bound inside the process.
- humanrebar 10y agoThat is certainly one approach, and the article agrees. > The root cause of this weakness is that the assert mechanism is designed purely for testing purposes, as is done in C++. However, C and C++ are perhaps unique in how much undefined behavior is possible and in how simple it is to create. Inserting into a vector while iterating through it, for instance. Or an uninitialized pointer. That's why many C++ experts believe in runtime assertions in production. Crashing the application with a core dump is generally preferable to trashing memory, corrupting your database, or launching the missiles.
- p4wnc6 10y agoAll of the C/C++ experts I know, as well as people who have interviewed me coming from primarily that background, have always been among the most adamant to stress that an application crashing unexpectedly should never happen and is always the wrong outcome. I imagine they would say that your statement about crashing vs. e.g. launching the missiles is a false dilemma. You don't crash and you don't incorrectly launch the missiles. I'm not a C++ developer so I can't say it with certainty. I more agree with what you're saying. I'm just relaying that my experience has been that out of many different language communities, C++ actually seems adamantly the opposite of what you're describing.
- philipov 10y agoIn my experience, "You don't crash" means you catch the exception and exit gracefully, reporting a fatal error has occurred. Users don't distinguish between a crash and a fatal error. Higher level languages are better at reporting uncaught runtime errors than C/C++ is, because they'll automatically do things like print useful stack traces and then exit gracefully even if you don't catch an exception. The interpreter doesn't crash when your code does.
- humanrebar 10y agoI think you misunderstand the use case. If your container is tracking work done and it thinks 20 requests were handled and only 10 were received, you have an invariant failure. Without more context, this could easily be trashed memory, in which case, you might already be in the middle of undefined behavior. In that case, getting the hell out of the process is the most responsible course of action. Efforts to even log what happened could be counterproductive. You might log inaccurate info or write garbage to the DB. Also, if you don't catch an exception in C++, most systems will give you a full core, which includes a stack trace for all running threads. Catching an exception and 'exiting cleanly' actually loses that information.
- tolmasky 10y agoCouldn't the assert message just say something like ", warning: this is only checked in development". I don't know, requirement of knowing how something works are always kind of tough since a lot of people's first interactions with things are in the code (like if they've just joined a new project), and they may assume they understand the functionality, and their assumptions may initially seem correct as they test it themselves. Its one of those "don't know what you don't know" scenarios, and "look up every function you ever see just in case what you think it does isn't what it actually does!" can be a bit impractical. So if this is known to be a gotcha, making the function itself speak that gotcha might be useful.