C++ Logo


Advanced search

Re: Re-purposing the function exception specification

From: <andrei_at_[hidden]>
Date: Tue, 30 Jun 2020 18:14:40 +0100
Good afternoon,

Thanks for the VERY useful insight into the programming-by-contract work.

I don't see why the "group #1" wants to continue after a contract
violation - it's like trying to call "double sqrt(double x) require: x
>= 0 { ... }" as "sqrt(-1)" - the obvious choice would be to throw
something like "bad_contract" on a violation (which should then never be
"checked"). I'll read up on this subject further, so thanks again.

Perhaps I wasn't clear in my original proposal: what I'm thinking about
is that


void foo() throws (a,b) { ... }


should mean "foo() can throw anything, but a and b must be handled
explicitly and/or propagated".

And you're correct in that a RAM-only implementation of e.g. an input
stream where "int read() throw(io_exception)" never actually throws is
an overkill... sometimes. Imagine we're writing a TEXT stream that reads
ASCII-7 characters only - suddenly even an in-RAM implementation may
throw "bad_data : public io_exception" if it encounters a byte that is
>= 128!


     Andrey Kapustin

On 30/06/2020 12:28, Henry Miller via Std-Proposals wrote:
> There are serious proposals to add programing by contract to C++. In
> fact it was in C++20 until the last minute when it was released some
> important details were not worked out yet and so removed so the rest
> of the standard could ship. SG21 officially exists to figure out how
> to get programing by contracts into C++. Nobody can guarantee it will
> happen, but it is an official effort.
> Contracts in C++ are trying to work out the differences between 3
> groups (note I'm not deep into contracts, but this is my
> understanding, so if someone says I'm wrong they are probably right) .
> Group 1 wants runtime control of what happens on breaking the contract
> : they may just log an error and continue in some cases. Group 2 wants
> to use whole program analysis to figure out if the program is correct,
> they believe they can find more errors with contracts, and are willing
> to let their analysis run for days. Group 3 wants the compiler to
> optimize around the contract if the input contract is no nullprt, they
> will remove nullprt checks found later. You can see group one and two
> are at odds, since if you can continue beyond a contract violation the
> optimizer can't assume the contract for optimization.
> Note that each of the above groups is perfectly valid in isolation.
> Different people have different priorities based on their domain and
> so for different people different views win as most important, but all
> are valid.
> Exception specifications are in my mind just another contract. A
> function won't return nullprt, a functions return is always greater
> than the input (implies something near INT_MAX). A function will only
> throw network error. The above 3 groups give us ways of thinking about
> what if we are wrong.
> I think unifying with contracts is good because it gives you a
> framework for talking about what Happens if I'm wrong. Obviously if
> you annotate everything that can't happen because it is trivial for a
> compiler to figure out where you failed to catch an exception. However
> if you are just starting to add annotations contracts give us the
> framework to reason about what we want to about violations.
> One issue with exception speciations as you propose them is that not
> all possible exceptions apply in some specific cases. Read() could
> throw a network error if you are reading from the network, but I know
> I'm an embedded system with no network interface and so why should I
> catch a network error just to make the exception specifiers happy that
> I don't throw it after calling read... Hopefully contracts let us say
> this is an axiom in my environment, without adding more new syntax.
> I hope that helps.
> On Mon, Jun 29, 2020, at 21:19, andrei--- via Std-Proposals wrote:
>> Good morning,
>> I'll have to think on what you wrote, and I thank you for the
>> feedback. Nevertheless, I'm not sure I understand your reasoning
>> entirely (unless I'm missing something) - so, please, elaborate. To
>> explain: to me a "programming-by-contract" always meant the
>> perception of functions (methods) as "services" which "require"
>> something from the caller and, in return, "ensure" something on
>> behalf of a callee. If I were to use a HYPOTHETICAL P-B-C syntax in a
>> C/C++ case, I could write:
>> =========================================================================
>> char * strchr(const char * str, int ch) require: str != nullptr;
>> require: ch != 0; ensure: (result == nullptr) || (result >= str &&
>> result < (str + strlen(str)) && *result == ch); { /* implementation
>> */ }
>> =========================================================================
>> Maybe this is influenced by me knowing only Eiffel as a language that
>> has a direct support for "programming-by-contract" (I have developed
>> another C-level one, but that's not important in this context). This,
>> by the way, is a feature that I would ALSO like to see becoming a
>> part of C++ standard, but I see no way of it ever becoming accepted
>> by the C++ committee. What's the difference from the "checked
>> exceptions" enforcement? I say it is: * In a correctly written
>> program no precondition/postcondition (contract) or assetrion
>> violations would ever be triggered. Any of these violations mean a
>> bug in the program. * In a correctly written program THAT RUNS IN A
>> PERFECT WORLD no exception would ever be thrown. There'll be no
>> "database_exception"s to signal that the DB engine is down, no
>> "bad_alloc"s to signal that we're out of free store, etc. * What I'm
>> proposing is to specialise the handling of exceptions that can occur
>> in a correctly written program running in an imperfect world. Can
>> "io_exception" happen? Yes, due to a genuine CRC error. Can a
>> "network_exception" happen? Yes, if the line is down. Can a
>> "bad_cast" happen? Yes, if the program is badly written, so
>> "bad_cast" should never be "checked". So, to recapitulate, I would
>> want, in a perfect world, for the C++ to offer both
>> programming-by-contract and checked-exceptions; but the two have a
>> different purpose: * P-B-C is a tool that can aid in program
>> verification (at compile-(!) and run-time), while * If "exception
>> handling" if a mechanism to make sure some errors "cannot be
>> ignored", then "checked exceptions" is a tool to ensure some of these
>> errors "cannot be ignored at compile time". Just an example of when I
>> may need both:
>> =========================================================================
>> class db_exception { ... }; class cursor { ... }; class database {
>> public: cursor get_first_record(void * rec) throw(db_exeption) //
>> throws "
>> db_exeption" on an I/O error require: rec != null;
>> // if, on entry, "rec" is "nullptr" we have a bug in the code { ... }
>> bool get_next_record(cursor & c, void * rec)
>> throw(db_exeption)
>> // throws "
>> db_exeption" on an I/O error
>> require: c != null; // if, on entry, "c" is "nullptr", it's a bug in
>> the code
>> require: rec != null;
>> //
>> if, on entry, "rec" is "nullptr" we have a bug in the code
>> ensure: (result == false) || // either the call failed... (old(c) >
>> c); // ...or, if it succeeded, the cursor has advanced
>> { ... }
>> };
>> =========================================================================
>> Incedentally, if I could get the C++ community interested in a
>> "programming-by-contract", I would also consider myself happy - but
>> that would require an extra syntax to the C++, which I have no chance
>> of getting past the C++ committees. Thirty-five years of practical
>> experience with two dozen languages are, naturally, no match for a
>> bunch of well-meaning one-language experts. Thanks again for your
>> response, and especially for talking about programming-by-contract -
>> I did not dare to raise that subject in a C++ world for fear of being
>> ridiculed. Andrey Kapustin
>> On 29/06/2020 14:49, Henry Miller via Std-Proposals wrote:
>>> On Fri, Jun 26, 2020, at 22:12, andrei--- via Std-Proposals wrote:
>>>> Good morning,
>>>> You have, indeed, convinced me that the "int foo() throws(auto)" is
>>>> a no-go and if it will never make it into the C++ language, the
>>>> better for that; your few well-chosen examples have been informative.
>>>> However, I'm still adamand that C++ needs to allow both un-checked
>>>> and checked exceptions for its practitioners, depending on their needs:
>>>> * If I'm a writer of a shared library heavy on templates, then
>>>> I'll never use this weird new feature, and my code will always
>>>> be a valid C++.
>>>> * If I'm a writer on a project where safety means all, I want
>>>> checked exceptions even more than I want programming-by-contract.
>>> After thinking about this for a few days I think this second
>>> statement is wrong: I think you want programing-by-contract with
>>> exceptions as one contract type. (post condition) By making
>>> exceptions a contract you unify with another part of the language
>>> instead of needing new syntax - this alone makes it more likely you
>>> can get someplace with your want. Contracts also give you
>>> more/better options for what if the exception happens anyway.
>>> Without going with contracts, checked exceptions are all or nothing
>>> which means almost nobody will retrofit them: they niche that only a
>>> few will use and thus not worth adding to the standard. With
>>> contracts you can start adding checked exceptions incrementally with
>>> choices for how to find out you are wrong, and choices for how to
>>> handle being wrong.
>>> I don't follow contracts closely (though I feel like I should), but
>>> I think joining them and improving their papers to address
>>> exceptions is a better step for you.
>> --
>> Std-Proposals mailing list
>> Std-Proposals_at_[hidden] <mailto:Std-Proposals_at_[hidden]>
>> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals

Received on 2020-06-30 12:18:01