Date: Sun, 21 Jun 2020 21:10:17 +0000
To quote the recent HOPL(*) paper by Bjarne:
Page 62: "There was always a group of people who wanted compile-time checks of which exceptions a
function could throw. That, of course, works well in type theory, with small programs, with fast
compilers, and with full control of the source code. The committee repeatedly rejected that idea on
the grounds that it doesn’t scale to million-line programs developed and maintained by dozens (or
more) organizations."
(*) https://www.stroustrup.com/hopl20main-p5-p-bfc9cd4--final.pdf
> -----Original Message-----
> From: Std-Proposals <std-proposals-bounces_at_[hidden]pp.org> On Behalf Of
> andrei--- via Std-Proposals
> Sent: Saturday, June 20, 2020 4:11 PM
> To: std-proposals_at_lists.isocpp.org
> Cc: andrei_at_[hidden]
> Subject: [std-proposals] Re-purposing the function exception specification
>
> In some situations I want checked exceptions (ALMOST Java style) to make sure
> thay are handled.
> I also want all my existing C++ code to keep working without any changes.
> I also want the use of "checked" exceptions to be a choice, not an enforced
> practice.
>
> What if we re-purpose the "<function header> throw(list-of-types)"
> syntax to mean "these exceptions
> are checked FOR THAT FUNCTION", i.e. make the list-of-checked-exceptions a
> property of a function (method, function type) - an exception class by itself is
> not "checked"
> or "unchecked":
>
> ============================================================
> class base_ex : public std::exception { ... } class derived_ex : public base_ex { ... }
>
> void foo() throws() { ... } // no exceptions thrown at all (==
> noexcept(true)) void zee() { ... } // may throw anything, no
> exceptions are "checked"
> void bla() throws (base_ex) { ... } // may throw anything, also "base_ex" is
> "checked"
> void umf() throws (derived_ex) { ... } // may throw anything, also "derived_ex"
> is "checked"
>
> void (*pfoo1)() throws() = foo; // OK
> void (*pfoo2)() throws() = zee; // Not OK, "zee" may throw but "*pfoo2" must
> not void (*pfoo3)() throws() = bla; // Not OK, "bla" may throw but "*pfoo3"
> must not void (*pfoo4)() throws() = umf; // Not OK, "umf" may throw but
> "*pfoo4" must not
>
> void (*pzee1)() = foo; // OK, "*pzee1" may throw, but "foo" will never do so
> void (*pzee2)() = zee; // OK void (*pzee3)() = bla; // Not OK, "*pzee3" has no
> "checked"
> exceptions, but "bla" has a "checked base_ex"
> void (*pzee4)() = umf; // Not OK, "*pzee4" has no "checked"
> exceptions, but "umf" has a "checked derived_ex"
>
> void (*pbla1)() throws(base_ex) = foo; // OK, "*pbla1" has a "checked
> base_ex", but "foo" will never throw it void (*pbla2)() throws(base_ex) =
> zee; // OK, "*pbla2" has a "checked base_ex", and "zee" may or may not
> throw it void (*pbla3)() throws(base_ex) = bla; // OK void (*pbla4)()
> throws(base_ex) = umf; // OK, "umf" has a "checked derived_ex" but "*pbla4"
> has checked "base_ex"
>
> void (*pumf1)() throws(derived_ex) = foo; // OK, "*pumf1" has a "checked
> derived_ex", but "foo" will never throw it void (*pumf2)() throws(derived_ex) =
> zee; // OK, "*pumf2" has a "checked derivede_ex", and "zee" may or may not
> throw it void (*pumf3)() throws(derived_ex) = bla; // Not OK, "*pumf" has a
> "checked derived_ex" but "bla" has checked "base_ex"
> void (*pumf4)() throws(derived_ex) = umf; // OK
>
> void huh1() { bla(); } // Not OK, the "checked base_ex" of "bla" is
> not handled or propagated void huh2() throw(base_ex) { umf(); } // OK, the
> "checked derived_ex" of "umf" is propagated out of "huh2"
> void huh3() { try { umf() } catch (const base_ex &) {}; } // OK, the "checked
> derived_ex" is handled by "catch"
> ============================================================
>
> The old "pound the function senseless if it throws something non on its
> throw(...) list" has been
> removed as of C++17 (I think), so there's no harm to any code written in
> C++17-or-later.
>
> Any pre-C++11 code that uses the old-style "throw(...)" semantics will
> still keep working, because
> when e.g. a "g++" is called the C++ version is specified explicitly with
> e.g. "-std=c++17".
>
> What do you think?
>
> Thanks in advance,
> Andrey Kapustin
> andrei_at_[hidden]
>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
Page 62: "There was always a group of people who wanted compile-time checks of which exceptions a
function could throw. That, of course, works well in type theory, with small programs, with fast
compilers, and with full control of the source code. The committee repeatedly rejected that idea on
the grounds that it doesn’t scale to million-line programs developed and maintained by dozens (or
more) organizations."
(*) https://www.stroustrup.com/hopl20main-p5-p-bfc9cd4--final.pdf
> -----Original Message-----
> From: Std-Proposals <std-proposals-bounces_at_[hidden]pp.org> On Behalf Of
> andrei--- via Std-Proposals
> Sent: Saturday, June 20, 2020 4:11 PM
> To: std-proposals_at_lists.isocpp.org
> Cc: andrei_at_[hidden]
> Subject: [std-proposals] Re-purposing the function exception specification
>
> In some situations I want checked exceptions (ALMOST Java style) to make sure
> thay are handled.
> I also want all my existing C++ code to keep working without any changes.
> I also want the use of "checked" exceptions to be a choice, not an enforced
> practice.
>
> What if we re-purpose the "<function header> throw(list-of-types)"
> syntax to mean "these exceptions
> are checked FOR THAT FUNCTION", i.e. make the list-of-checked-exceptions a
> property of a function (method, function type) - an exception class by itself is
> not "checked"
> or "unchecked":
>
> ============================================================
> class base_ex : public std::exception { ... } class derived_ex : public base_ex { ... }
>
> void foo() throws() { ... } // no exceptions thrown at all (==
> noexcept(true)) void zee() { ... } // may throw anything, no
> exceptions are "checked"
> void bla() throws (base_ex) { ... } // may throw anything, also "base_ex" is
> "checked"
> void umf() throws (derived_ex) { ... } // may throw anything, also "derived_ex"
> is "checked"
>
> void (*pfoo1)() throws() = foo; // OK
> void (*pfoo2)() throws() = zee; // Not OK, "zee" may throw but "*pfoo2" must
> not void (*pfoo3)() throws() = bla; // Not OK, "bla" may throw but "*pfoo3"
> must not void (*pfoo4)() throws() = umf; // Not OK, "umf" may throw but
> "*pfoo4" must not
>
> void (*pzee1)() = foo; // OK, "*pzee1" may throw, but "foo" will never do so
> void (*pzee2)() = zee; // OK void (*pzee3)() = bla; // Not OK, "*pzee3" has no
> "checked"
> exceptions, but "bla" has a "checked base_ex"
> void (*pzee4)() = umf; // Not OK, "*pzee4" has no "checked"
> exceptions, but "umf" has a "checked derived_ex"
>
> void (*pbla1)() throws(base_ex) = foo; // OK, "*pbla1" has a "checked
> base_ex", but "foo" will never throw it void (*pbla2)() throws(base_ex) =
> zee; // OK, "*pbla2" has a "checked base_ex", and "zee" may or may not
> throw it void (*pbla3)() throws(base_ex) = bla; // OK void (*pbla4)()
> throws(base_ex) = umf; // OK, "umf" has a "checked derived_ex" but "*pbla4"
> has checked "base_ex"
>
> void (*pumf1)() throws(derived_ex) = foo; // OK, "*pumf1" has a "checked
> derived_ex", but "foo" will never throw it void (*pumf2)() throws(derived_ex) =
> zee; // OK, "*pumf2" has a "checked derivede_ex", and "zee" may or may not
> throw it void (*pumf3)() throws(derived_ex) = bla; // Not OK, "*pumf" has a
> "checked derived_ex" but "bla" has checked "base_ex"
> void (*pumf4)() throws(derived_ex) = umf; // OK
>
> void huh1() { bla(); } // Not OK, the "checked base_ex" of "bla" is
> not handled or propagated void huh2() throw(base_ex) { umf(); } // OK, the
> "checked derived_ex" of "umf" is propagated out of "huh2"
> void huh3() { try { umf() } catch (const base_ex &) {}; } // OK, the "checked
> derived_ex" is handled by "catch"
> ============================================================
>
> The old "pound the function senseless if it throws something non on its
> throw(...) list" has been
> removed as of C++17 (I think), so there's no harm to any code written in
> C++17-or-later.
>
> Any pre-C++11 code that uses the old-style "throw(...)" semantics will
> still keep working, because
> when e.g. a "g++" is called the C++ version is specified explicitly with
> e.g. "-std=c++17".
>
> What do you think?
>
> Thanks in advance,
> Andrey Kapustin
> andrei_at_[hidden]
>
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
Received on 2020-06-21 16:13:32