C++ Logo

std-proposals

Advanced search

Re: P2192 R1 -- request for comments

From: Jason McKesson <jmckesson_at_[hidden]>
Date: Fri, 11 Sep 2020 12:29:54 -0400
On Fri, Sep 11, 2020 at 5:19 AM Dusan Jovanovic (DBJ) via
Std-Proposals <std-proposals_at_[hidden]> wrote:
>
> Many thanks for the time spent on this. My answers are inline.
>
> On Fri, 11 Sep 2020 at 00:56, Jason McKesson via Std-Proposals <std-proposals_at_[hidden]> wrote:
>>
>> On Thu, Sep 10, 2020 at 1:38 PM Dusan Jovanovic (DBJ) via
>> Std-Proposals <std-proposals_at_[hidden]> wrote:
> DBJ > crt_proxy_lib : https://github.com/dbj-systems/libstdc-error/tree/crt_proxy_lib/crt_proxy_lib . "metastate" + "valstat" achieve the "returns handling" minus complex and special return types.

But it doesn't do that. It doesn't do *anything* because your current
`valstat` is a non-type. It is just a thing that holds two things,
which are things that are expected to do something, but without any
serious declaration as to what such things are required to do or
without any meaning attached to the results of doing those things.

In your quest to not be "complex", you have removed *functionality*
and purpose. The only "purpose" left is that it's a decomposable
aggregate of two values.

`valstat` is like if C++ had a `container<T>` template, where `T` is
what gets stored in the `container`. Except that in order to be as
generic as possible, `container<T>` is just a struct with a `T` in it,
and this `T` is expected to implement all of the container
functionality that you personally need to use. But different people
will have different container APIs for their `T`s, so there is zero
interoperability for it; you can't take someone's `container<T>` and
expect to use it without intimate knowledge of what their particular
`T` is.

`container<T>` would certainly be an uncomplicated type. It could
interop with any other language. One could even call it a "paradigm
shift" in how we deal with containers.

But one thing you couldn't call it is *useful*.

That's what `valstat` is. It's a type that doesn't do anything, which
implements a conceptual framework that imposes no requirements or
expectations on the code. It's so generic that it doesn't do anything
or mean anything or accomplish anything.

> DBJ> I have a question or two, if I may? What is your advice for projects from the motivation section? And. What is your advice for (let's say) C++ projects using std lib, regarding "error handling" design?

I do find it interesting that you are asking me about "error handling"
in the context of a proposal where the very first sentence is a
statement that it's not about "error handling". So you probably ought
to remove that sentence ;)

In any case, my advice is that I rank error handling mechanisms in a
priority order. Start from the highest priority and discard it if it
would violate some technical requirement of the application. That
order being:

1. exceptions
2. multi-channel return value (expected/outcome/etc)
3. output parameters
4. out-of-band error reporting

When/if P0709 gets through, you can replace "exceptions" with "static
exceptions".

As for the users in the scenario you suggest, I would say that your
motivation section is basically designing out all other possibilities
arbitrarily. There are technical reasons not to use exceptions. There
are no technical reasons not to use output parameters or out-of-band
error reporting. They may not be great solutions, but they are
*functional* solutions to those problems. So if those solutions are
warranted, they should be used.

Basically, I don't buy that there is a realistic path to a
one-size-fits-all solution to handling every form of
errors/status/disappointment/etc in C++. You're going to have to
exercise judgment for each individual API and pick the one that works
best for that API's needs, living within the limitations thereof.

> I am simply postulating expected, outcome and the rest, are not required. Also too complicated and narrowly focused on C++, in modern projects where C++ is just a tiny part of the architecture of a cloud-side system. As an architect, I can jump in and out of different languages but keeping the same "idiom"(valstat) or "paradigm" (metatstate). Think WASM combination of javascript, C and C++.

OK, I believe that this is the first time you've mentioned interop
with other languages. Which is also the first time when you've given a
legitimate problem that your type solves which other types not only do
not solve, but *cannot* solve. It's also the first time that I've been
able to understand a purpose to this proposal and what a seemingly
pointless type like `valstat` is supposed to mean.

`valstat` is a generic transport mechanism for data. That's what
you're trying to build: a lingua franca for communicating
error/status/etc data between different languages that work in
different ways, perhaps in the context of WASM and so forth. This is
the only place where the non-existence of features actually makes
sense, because it's designed to be a lowest-common denominator.

`std::valstat` is a C++ template. As such, C code cannot return that
type. I don't know much about WASM or that sort of thing, but
following the C and C++ object models, C can't return `valstat`. It
also can't return a type that works like `std::valstat`, except in the
most basic sense: a struct containing two values. This is why there's
no mechanism in your proposal to actually comprehend the results:
because C couldn't deliver a type that implements such a mechanism,
since those mechanisms would inherently be C++ based (overloading,
ADL, customization points, concepts, etc).

Here's the problem: if this lingua franca provides no immediate
benefits for C++ users working in C++ code bases, it will never be
widely adopted. It would only ever be used in the context of
transporting error/status/etc data between other languages.

So while it is interesting to think of this "metastate" paradigm as a
way to make C++ more interop-friendly, unless it provides genuine
functionality to C++ users, it's never going to get far.

Received on 2020-09-11 11:33:36