On Tue, Jan 16, 2018 at 01:38:25AM -0800, smarie wrote:
Typically ‘assert isfinite(x)‘ is today a good example of what is wrong:
1. it can be disabled globally by end-users even if the lib developer does not want it,
That's not a bug, or even a problem ("wrong"), it is the very purpose of assert. Assertions are intended to allow the end user to disable the checks. If you, the developer, don't want a check to be disabled, then you shouldn't call it an assertion and use assert. I sometimes wish that Python included a richer set of assertions rather than just a single `assert` keyword. Something like Eiffel's concept of pre-conditions, post-conditions and invariants, where each can be enabled or disabled independently. But even with Python's sparse assertion API, the reason for assert is for debugging checks which can optionally be disabled. Checks which should never be disabled don't belong as assertions.
2. if x is None the exception is different from the exception you get if x is not finite
This is a little untidy, but I don't see why this should be considered "wrong". That's just the way Python operates: however you write a check, it is going to rely on the check succeeding, and if it raises an exception, you will see that exception. That's a good thing, not "wrong" -- if my assertion isfinite(x) fails because x is None, I'd much rather see a TypeError than AssertionError: x is not finite
3. you can not customize the exception type for easy error codes internationalization, you can only customize the message.
assert is not intended to be used to present user-friendly error messages to the end-user. The end-user should never see an AssertionError, and if they do, that's a bug, not a recoverable error or an avoidable environmental/input error. I have come to the conclusion that a good way to think about assertions is that they are often "checked comments". Comments like: # when we get here, x is a finite number quickly get out of sync with code. To quote Michael Foord: "At Resolver we've found it useful to short-circuit any doubt and just refer to comments in code as 'lies'. " -- Michael Foord paraphrases Christian Muirhead on python-dev, 2009-03-22 Instead, turn it into an assertion, if you can: assert isfinite(x) which is both inline developer documentation ("x is a finite number") and a debugging aid (it will fail during development is x is not a finite number). And, if the cost of those assertions becomes excessive, the end-user can disable them.
My proposal would be to rather define another statement for example
'validate <expression> <exception, exception_type or exception_message>'
The problem with a statement called "validate" is that it will break a huge number of programs that already include functions and methods using that name. But apart from the use of a keyword, we already have a way to do almost exactly what you want: if not expression: raise ValidationError(message) after defining some appropriate ValidationError class. And it is only a few key presses longer than the proposed: validate expression, ValidationError, message -- Steve