On Thu, Sep 09, 2021 at 12:02:13PM -0400, Juancarlo Añez wrote:
> Steven,
> 
> The purpose is to make it easier to make software more resilient.

Thank you but I understand the purpose of DBC and how it can be helpful 
for writing resilient software. If you search the archives, you will see 
that not only have Eiffel-style contracts been discussed before, but I 
am a great proponent of them.

What I question is that allowing assert to raise non-assertions will 
lead to *more* resilient software rather than less.

I know far too many people who insist on abusing assertions as a lazy 
way to validate caller- or user-supplied data, which is **not** a 
contract. Contracts apply only to calls between parts of your own 
application. Contracts do not apply to:

- checking external data, which can be corrupt or invalid;

- checking data provided by the end-user, who can never be trusted
  to keep to the contract;

- checking input in library functions that may be called by other
  libraries or programs that are not a party to the contract;

but I see too many people doing exactly that because it saves them a 
line of code. And because they are abusing assert, that means that their 
software is *less* resilient, because it will fail to perform those 
checks if the end-user runs it with assertions disabled.

If `assert` can be used to raise *any* sort of exception, not just 
AssertionError, that will encourage that abuse and lead to less 
resilient software, not more.


> IOW, my premise is that we should be using *_lots_* of assertions,
> *_always_*, and that for that we need to make them easier to write,

How can assertions be easier to write than they are now?

    assert condition

You don't get any easier than that.

That is the bare minimum needed for contract checking.


> and easier to handle in the event of the unavoidable failures.

If you believe that contract violations are *unavoidable* then you have 
misunderstood the purpose of DBC.

Contracts apply between parts of your application. A contract violation 
is a *bug in your application* and so is completely avoidable.

(Except in the sense that we are all imperfect and therefore all 
software contains bugs, nevertheless we can asymptopically approach the 
status of being free from bugs.)

Contracts do not apply between libraries and their callers, or between 
software and end-users. That would be rude and hostile, and the opposite 
of resilient.

*Data and input validation* errors are unavoidable: there will always be 
corrupt files, incorrect data, arguments passed in the wrong order, etc. 
But they are not contracts and should not be tested for using assert 
because we cannot ever safely disable that validation.

The point of assertions and contracts is that you *don't catch them*. 
Assertions and contracts are hard requirements. If the contract is 
violated you have a bug in your software and the only safe thing to do 
is to log the error and gracefully exit.

If you can catch and recover from an error, its not a contract 
violation. It's just using exceptions for flow control.

    # Exceptions as flow control.
    # LBYL
    if condition:
        do_this()
    else:
        do_that()

    # EAFP
    try:
        do_this()
    except ConditionFailure:
        do_that()


> Seeking
> unit-test coverage is not enough because unit tests don't run in production.

If you do DBC correctly, contract assertions don't run in production 
either. It is up to the end-user whether the contracts run or not.

(I believe that the Eiffel community tends to recommend that pre- 
condition testing remain in production, and that post-conditions, 
invariants and other contracts be disabled, but that's entirely under 
the control of the end-user.)

One simple test for whether something can be a contract or not is this:

Could it be safe for me to remove this test? Not necessarily today, but 
some day, in the future, when I am confident that the code is bug free.

If your answer is Yes, then it could be a contract written with assert.
 
But if the answer is No, or I Don't Know, then it cannot be a contract, 
and it should not be written using assert.



-- 
Steve
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/python-ideas@python.org/message/76H7642S6DU4HDMMO5E44AASKVZG5FAD/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to