C++ Logo

std-proposals

Advanced search

Re: Re-purposing the function exception specification

From: <andrei_at_[hidden]>
Date: Mon, 22 Jun 2020 20:44:08 +0100
Thanks again for pointing to a dark corner in my proposal.

For the template problem I can see at least 2 solutions (and would
propose allowing both in the language).

1. Traditional-style: if the templates be the problem, let the templates
be the solution:
============================================================
class storage_exception { ... };
class database_exception { ... };

template <class T> struct storage_traits
{
   const int max_record_length = 1000;
   using service_exception = storage_exception;
};

template <> struct storage_traits<database_storage>
{
   const int max_record_length = 2000;
   using service_exception = database_exception;
};

class file_storage
{
   bool read_record(char record[1000]) throw(storage_exception);
};

class database_storage
{
   bool read_record(char record[2000]) throw(database_exception);
};

template <class T>
void validate(T & storage) throw(typename
storage_traits<T>::service_exception)
{
   char record[storage_traits<T>::max_record_length];
   while (storage.read_record(record)) ...
}
============================================================

2. New-style: let the compiler deduce (the "auto" keyword already means
"let compiler determine the type"!)
============================================================
class storage_exception { ... };
class database_exception { ... };

template <class T> struct storage_traits
{
   const int max_record_length = 1000;
}

template <> struct storage_traits<database_storage>
{
   const int max_record_length = 2000;
}

class file_storage
{
   bool read_record(char record[1000]) throw(storage_exception);
}

class database_storage
{
   bool read_record(char record[2000]) throw(database_exception);
}

template <class T>
void validate(T & storage) throw(auto) // the compiler "knows" which
"checked" exceptions are not handled
{
   char record[storage_traits<T>::max_record_length];
   while (storage.read_record(record)) ... // the compiler "knows" what
is "checked" for "T::readRecord()"
}
============================================================

What do you think?

I agree when you say "C++ exceptions are what you use when you want the
set of yieldable things to be open-ended", and I'm not proposing to
change that. I just want the programmer to be able to choose between
open-ended-ness and safety on a per-function basis.

     Andrey Kapustin

On 21/06/2020 23:15, Arthur O'Dwyer via Std-Proposals wrote:
> On Sun, Jun 21, 2020 at 5:10 PM Michael Hava via Std-Proposals
> <std-proposals_at_[hidden]
> <mailto:std-proposals_at_[hidden]>> wrote:
>
> To quote the recent HOPL paper
> <https://www.stroustrup.com/hopl20main-p5-p-bfc9cd4--final.pdf> 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."
>
>
> Concretely, one of the ways C++ lets you write big programs "without
> full control of the source code" is templates.
> Andrey, you'd have to figure out what to do about templates:
>
> struct ErrA {};
> struct ErrB {};
> struct SA {
> void foo() throw(ErrA);
> };
> struct SB {
> void foo() throw(ErrB);
> };
> template<class T>
> void foo(T t) throw(???) {
> t.foo();
> }
>
> C++ already has several properties that can be propagated from callee
> to caller with enough effort: noexceptness, well-formedness (SFINAE).
> It has a few that cannot be propagated without loss: explicitness,
> overload-resolution-priority, constrainedness (C++20).
> At the moment, you're asking to add another property that can't be
> propagated. Can you fix that somehow?
>
> Herb Sutter's "Herbceptions" have basically the same problem with
> templates (last I checked): they add a new property that we'd like to
> propagate but it is ugly and/or inefficient to do so. I refer to these
> kinds of property as "colorations"; see e.g.
> https://quuxplusone.github.io/blog/2018/03/16/async-roundup/#the-concept-of-function-coloring (less
> about herbceptions)
> https://groups.google.com/a/isocpp.org/forum/#!topic/sg14/A05A5feSZYI (more
> about herbceptions)
>
> In general I kind of like the idea of statically checking "this
> function may yield a result /or/ an ErrA, and so all callers must
> handle ErrA"; but if you're actually in that situation today, why not
> just return a `variant` or `Expected` type instead? C++ exceptions are
> what you use when you /want/ the set of yieldable things to be open-ended.
>
> –Arthur
>

Received on 2020-06-22 14:47:23