Topic: Feedback requested on D0762R0 draft 1:
Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Tue, 03 Oct 2017 19:25:31 +0200
Raw View
On 10/03/2017 04:43 AM, Nicol Bolas wrote:
> The moment the standard starts requiring a specific implementation is the moment it stops being a standard and starts being an implementation of some standard. The committee doesn't "historically" dictate implementations because /it's not their job/.
Well, the standard certainly shouldn't prescribe a specific
implementation, but it could prescribe certain properties
that are useful, for example when interacting with C.
See, for example, std::pair: It has a trivial destructor if
both involved types have trivial destructors.
We could similarly prescribe the triviality of copy and move
constructors.
Now, it's obviously hard to argue about C compatibility for
something that is a template and has a plethora of interesting
constructors. However, we already attempt something like
that for std::complex; see 29.5 p4 [complex.numbers].
Maybe we want to say something like std::result and a struct X
consisting of T, unsigned int, and E members have a common
initial sequence that is all of X.
Jens
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/59D3C80B.4050402%40gmx.net.
.
Author: "Arthur O'Dwyer" <arthur.j.odwyer@gmail.com>
Date: Tue, 3 Oct 2017 11:27:21 -0700
Raw View
--f403045c0b6064d03b055aa8a4fa
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
First, I should also say thank you to Jens Maurer for writing that initial
reply to Niall's paper, since I wouldn't have looked at the paper if Jens
hadn't done so first. Even if it turned out that that paper is already
obsolete in Niall's view.
This thread is getting super tangled, so I won't try to respond directly to
any quotes in context; I'll just list some of my opinions in the order I
come to them. If something here looks like I'm agreeing-with or
contradicting something you personally said in this thread, then yeah, I'm
probably responding to you. ;)
(1) A default-constructed std::error_code is absolutely an "ok, no error"
value. In fact, for any enumeration type E where is_error_code_enum_v<E>,
the value static_cast<E>(0) must be the "ok, no error" value. I think we
are all in agreement that the Standard strongly implies that stuff breaks
if you deviate from this informal rule. Niall referred to the absence of
normative wording as "really a defect." Yes it is. I would like us all to
assume that the defect will be fixed, and waste no further verbiage on
pedantry in that area.
(2) Re a tricky idea Jens suggested: `make_error_code(E)` should not do any
value-munging "tricks" (such as remapping E(200) to int(0), or E(0) to
int(200)), because such tricks would should be undone by
`static_cast<E>(ec.code())`, and those semantics are 100% nailed down by
the Standard.
(3) It seems very important to Niall that the Expected/Result type that is
standardized should have a normatively defined class definition, so that
anyone could look at the Standard wording and deduce exactly how to
interoperate with Expected/Result from C code or from pre-C++2a code. I
sympathize with this idea. I think Nicol was right when he said that the
C++ Standard generally does *not* standardize class definitions. So just be
aware that you will be swimming upstream to get this =E2=80=94 especially i=
f you
want a non-standard-layout class with special member functions, private
members, etc etc. Jens gives the example of std::complex.
(4) I believe that the world would be a better place if the C++ Standard
*did* sometimes standardize class definitions. And the world would be
better if they *did* sometimes standardize a function's behavior via
"reference implementation."
(5) I still believe that it is a sin to subclass std::error_code,
std::exception_ptr, or any other std:: class type that is not already part
of a classical hierarchy. Composition/aggregation is okay. Inheritance is
not. You will get slicing and you will get bugs.
(6) Jens's example use-case #4 almost convinced me that
implicit-construction-from-the-E-type is desirable. `if (!cwd) return
cwd.error()` is easier on the eyes than `if (!cwd) return
make_unexpected(cwd.error())`. However, I wonder whether we could get the
best of both worlds by providing a convenience member function: `if (!cwd)
return cwd.unexpected()`. For the long-term problems caused by implicit
conversions involving vocabulary types, please see the ongoing fiasco of
std::string, std::string_view, std::filesystem::path. Eliminating implicit
conversions from your C++ code eliminates bugs. Eliminating implicit
conversions from your proposals eliminates literally YEARS of work for the
future members of the Committee.
(7) I don't like the term "never-empty variant." Even Anthony Williams'
P0110 (which explores the idea of making a variant twice as big as
std::variant so that the new object could always be constructed before the
old one was destroyed) finally admits that he made emplace<T>() destroy the
old object before constructing the new one, and that means that his variant
*also* has an empty state. A variant which *requires* an empty state to
exist is not "never-empty."
(8) I certainly hope that both Result<T,E> and Expected<T,E> are "X"
whenever both T and E are "X", for values of "X" including at least
"trivially copyable" and "trivially destructible". If some implementation
of Result or Expected does not provide those guarantees, then that's a QoI
issue against that implementation. (I hope that the version that gets
standardized will have normative wording *requiring* those guarantees. If
that happens, then implementations without those guarantees will be
non-conforming.)
(9) Niall wrote: "If you are adding a feature which uses 98% of an existing
feature, then the standard should require use of that existing feature." I
strongly disagree with that statement. Now, I *do* think (and I think Niall
might agree) that we should not add new features with small gratuitous
quirks that make them impossible to implement in terms of other standard
features. To take two examples of the "gratuitous quirk" problem:
std::packaged_task<R(A...)> is not implementable in terms of
std::function<R(A...)> because copyability, and std::vector<T,A>::resize is
not implementable in terms of std::uninitialized_move_if_noexcept() because
allocator_traits. Therefore, if it were truly *impossible* to implement
Expected<T,E> in terms of std::variant<T,E>, I'd complain.
HOWEVER, I repeat that no sane implementation should pull in <variant> as a
result of including <expected>. The former is a "higher-level" feature than
the latter; it includes a ton of TMP machinery that is not needed by
<expected>. I might expect both headers to include some "helper" header
providing just the common parts needed by both.
We see an example of this in both libstdc++ and libc++, where <set> and
<map> are implemented in terms of a "helper" header sometimes named
<__tree>. It is theoretically possible to implement std::map<K,V> in terms
of std::set<something_clever<K,V>>, but no sane implementation will pull in
all of <set> as a result of including <map>.
I hope this clarifies my position.
(10) Speaking of "levelization", I do like the idea of having
"higher-level" and "lower-level" headers in the STL. I think it's
unfortunate that <system_error> =E2=80=94 which sounds like a low-level hea=
der =E2=80=94
actually depends on <string>, which recursively depends on most of the STL
(<string_view>, <ostream>, et cetera). I talked to Charley about this at
CppCon: I'm ambivalent. On the one hand I think it really sucks that
<system_error> has any dependencies at all. On the other hand, I appreciate
the idea of "vocabulary types," and it feels hypocritical to condemn the
library's own use of `std::string` as the vocabulary type for returning a
string.
(11) Niall writes: "Outcome uses struct storage, not union storage."
The paper Jens and I were reading flatly contradicts that statement, on
page 4, where it says "Result requires the following layout to be
implemented:" and then shows a piece of code involving a union. However,
the reference C implementation
on page 14 uses a non-union struct, and the reference C++ implementation on
page 17 uses a "non-standard" optional<T> with the caveats listed in a
comment at the bottom of page 16. It would be much *much* clearer if the
new paper didn't imply the use of a union/optional/variant; it would save
Niall a lot of argumentation. If you want a standard-layout struct, just
use one! Don't even put "union" in your sample code!
(12) Niall writes: "E is not necessarily an error for Expected. It's merely
an 'unexpected'." This is a distinction without a difference. Whether we
call it an "error", an "unexpected result", or an "exceptional state", the
point is that it's a "disappointment" (to use Lawrence Crowl's term). The
user's expectations are that foo.value() will give them the normal-path
result (if any), and that foo.error() will give them the
"disappointment-path" result (if any). Jens points out, rightly, that if
the user asks for foo.error() and there is no disappointment to report, it
makes some sense to return "no error" as opposed to blowing up the program
via a thrown exception or via undefined behavior. As to the question of
whether we can generally consider a default-constructed E to indicate "no
error", please see my point (1) in this email.
(13) I don't see the usefulness of outcome<X,Y,Z>; but I know that if I
don't like it I can avoid using it, and it sounds like Niall is not
proposing that one for standardization anyway. (That is, he's proposing it
for Boost.Outcome but not for C++2a.)
=E2=80=93Arthur
--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CADvuK0%2B4x1LUi%3DzAxDz2TY8af%3DGPxis5rnmcLLjYF=
TQe7fbQJg%40mail.gmail.com.
--f403045c0b6064d03b055aa8a4fa
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>First, I should also say thank you to Jens Maurer for=
writing that initial reply to Niall's paper, since I wouldn't have=
looked at the paper if Jens hadn't done so first. Even if it turned ou=
t that that paper is already obsolete in Niall's view.<br></div><div><b=
r></div><div>This thread is getting super tangled, so I won't try to re=
spond directly to any quotes in context; I'll just list some of my opin=
ions in the order I come to them. If something here looks like I'm agre=
eing-with or contradicting something you personally said in this thread, th=
en yeah, I'm probably responding to you. ;)</div><div><br></div><div><b=
r></div><div>(1) A default-constructed std::error_code is absolutely an &qu=
ot;ok, no error" value. In fact, for any enumeration type E where is_e=
rror_code_enum_v<E>, the value static_cast<E>(0) must be the &q=
uot;ok, no error" value. I think we are all in agreement that the Stan=
dard strongly implies that stuff breaks if you deviate from this informal r=
ule. Niall referred to the absence of normative wording as "really a d=
efect." Yes it is. I would like us all to assume that the defect will =
be fixed, and waste no further verbiage on pedantry in that area.</div><div=
><br></div><div>(2) Re a tricky idea Jens suggested: `make_error_code(E)` s=
hould not do any value-munging "tricks" (such as remapping E(200)=
to int(0), or E(0) to int(200)), because such tricks would should be undon=
e by `static_cast<E>(ec.code())`, and those semantics are 100% nailed=
down by the Standard.</div><div><br></div><div>(3) It seems very important=
to Niall that the Expected/Result type that is standardized should have a =
normatively defined class definition, so that anyone could look at the Stan=
dard wording and deduce exactly how to interoperate with Expected/Result fr=
om C code or from pre-C++2a code. I sympathize with this idea. I think Nico=
l was right when he said that the C++ Standard generally does *not* standar=
dize class definitions. So just be aware that you will be swimming upstream=
to get this =E2=80=94 especially if you want a non-standard-layout class w=
ith special member functions, private members, etc etc. Jens gives the exam=
ple of std::complex.</div><div><br></div><div>(4) I believe that the world =
would be a better place if the C++ Standard *did* sometimes standardize cla=
ss definitions. And the world would be better if they *did* sometimes stand=
ardize a function's behavior via "reference implementation."<=
/div><div><br></div><div>(5) I still believe that it is a sin to subclass s=
td::error_code, std::exception_ptr, or any other std:: class type that is n=
ot already part of a classical hierarchy. Composition/aggregation is okay. =
Inheritance is not. You will get slicing and you will get bugs.</div><div><=
br></div><div>(6) Jens's example use-case #4 almost convinced me that i=
mplicit-construction-from-the-E-type is desirable. `if (!cwd) return cwd.er=
ror()` is easier on the eyes than `if (!cwd) return make_unexpected(cwd.err=
or())`. However, I wonder whether we could get the best of both worlds by p=
roviding a convenience member function: `if (!cwd) return cwd.unexpected()`=
.. For the long-term problems caused by implicit conversions involving vocab=
ulary types, please see the ongoing fiasco of std::string, std::string_view=
, std::filesystem::path. Eliminating implicit conversions from your C++ cod=
e eliminates bugs. Eliminating implicit conversions from your proposals eli=
minates literally YEARS of work for the future members of the Committee.</d=
iv><div><br></div><div>(7) I don't like the term "never-empty vari=
ant." Even Anthony Williams' P0110 (which explores the idea of mak=
ing a variant twice as big as std::variant so that the new object could alw=
ays be constructed before the old one was destroyed) finally admits that he=
made emplace<T>() destroy the old object before constructing the new=
one, and that means that his variant *also* has an empty state. A variant =
which *requires* an empty state to exist is not "never-empty."</d=
iv><div><br></div><div>(8) I certainly hope that both Result<T,E> and=
Expected<T,E> are "X" whenever both T and E are "X&qu=
ot;, for values of "X" including at least "trivially copyabl=
e" and "trivially destructible". If some implementation of R=
esult or Expected does not provide those guarantees, then that's a QoI =
issue against that implementation. (I hope that the version that gets stand=
ardized will have normative wording *requiring* those guarantees. If that h=
appens, then implementations without those guarantees will be non-conformin=
g.)</div><div>=C2=A0</div><div>(9) Niall wrote: "If you are adding a f=
eature which uses 98% of an existing feature, then the standard should requ=
ire use of that existing feature." =C2=A0I strongly disagree with that=
statement. Now, I *do* think (and I think Niall might agree) that we shoul=
d not add new features with small gratuitous quirks that make them impossib=
le to implement in terms of other standard features. To take two examples o=
f the "gratuitous quirk" problem: std::packaged_task<R(A...)&g=
t; is not implementable in terms of std::function<R(A...)> because co=
pyability, and std::vector<T,A>::resize is not implementable in terms=
of std::uninitialized_move_if_noexcept() because allocator_traits. Therefo=
re, if it were truly *impossible* to implement Expected<T,E> in terms=
of std::variant<T,E>, I'd complain.</div><div>HOWEVER, I repeat =
that no sane implementation should pull in <variant> as a result of i=
ncluding <expected>. The former is a "higher-level" feature=
than the latter; it includes a ton of TMP machinery that is not needed by =
<expected>. I might expect both headers to include some "helper&=
quot; header providing just the common parts needed by both.</div><div>We s=
ee an example of this in both libstdc++ and libc++, where <set> and &=
lt;map> are implemented in terms of a "helper" header sometime=
s named <__tree>.=C2=A0 It is theoretically possible to implement std=
::map<K,V> in terms of std::set<something_clever<K,V>>, b=
ut no sane implementation will pull in all of <set> as a result of in=
cluding <map>.</div><div>I hope this clarifies my position.</div><div=
><br></div><div>(10) Speaking of "levelization", I do like the id=
ea of having "higher-level" and "lower-level" headers i=
n the STL. I think it's unfortunate that <system_error> =E2=80=94=
which sounds like a low-level header =E2=80=94 actually depends on <str=
ing>, which recursively depends on most of the STL (<string_view>,=
<ostream>, et cetera). I talked to Charley about this at CppCon: I&#=
39;m ambivalent. On the one hand I think it really sucks that <system_er=
ror> has any dependencies at all. On the other hand, I appreciate the id=
ea of "vocabulary types," and it feels hypocritical to condemn th=
e library's own use of `std::string` as the vocabulary type for returni=
ng a string.</div><div><br></div><div>(11) Niall writes: "Outcome uses=
struct storage, not union storage."</div><div>The paper Jens and I we=
re reading flatly contradicts that statement, on page 4, where it says &quo=
t;Result requires the following layout to be implemented:" and then sh=
ows a piece of code involving a union. However, the reference C implementat=
ion</div><div>on page 14 uses a non-union struct, and the reference C++ imp=
lementation on page 17 uses a "non-standard" optional<T> wi=
th the caveats listed in a comment at the bottom of page 16.=C2=A0 It would=
be much *much* clearer if the new paper didn't imply the use of a unio=
n/optional/variant; it would save Niall a lot of argumentation. If you want=
a standard-layout struct, just use one! Don't even put "union&quo=
t; in your sample code!</div><div><br></div><div>(12) Niall writes: "E=
is not necessarily an error for Expected. It's merely an 'unexpect=
ed'." This is a distinction without a difference. Whether we call =
it an "error", an "unexpected result", or an "exce=
ptional state", the point is that it's a "disappointment"=
; (to use Lawrence Crowl's term). The user's expectations are that =
foo.value() will give them the normal-path result (if any), and that foo.er=
ror() will give them the "disappointment-path" result (if any). J=
ens points out, rightly, that if the user asks for foo.error() and there is=
no disappointment to report, it makes some sense to return "no error&=
quot; as opposed to blowing up the program via a thrown exception or via un=
defined behavior. As to the question of whether we can generally consider a=
default-constructed E to indicate "no error", please see my poin=
t (1) in this email.</div><div><br></div><div>(13) I don't see the usef=
ulness of outcome<X,Y,Z>; but I know that if I don't like it I ca=
n avoid using it, and it sounds like Niall is not proposing that one for st=
andardization anyway. (That is, he's proposing it for Boost.Outcome but=
not for C++2a.)</div><div><br></div><div>=E2=80=93Arthur</div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CADvuK0%2B4x1LUi%3DzAxDz2TY8af%3DGPxi=
s5rnmcLLjYFTQe7fbQJg%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfoote=
r">https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CADvuK0%2B4=
x1LUi%3DzAxDz2TY8af%3DGPxis5rnmcLLjYFTQe7fbQJg%40mail.gmail.com</a>.<br />
--f403045c0b6064d03b055aa8a4fa--
.
Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date: Tue, 3 Oct 2017 21:40:51 +0300
Raw View
On 3 October 2017 at 21:27, Arthur O'Dwyer <arthur.j.odwyer@gmail.com> wrote:
> (5) I still believe that it is a sin to subclass std::error_code,
> std::exception_ptr, or any other std:: class type that is not already part
> of a classical hierarchy. Composition/aggregation is okay. Inheritance is
> not. You will get slicing and you will get bugs.
Fascinating. I didn't realize the writings that people usually use to
define what is a sin
talk about C++. I must update my understanding. :) With that
digression aside, presumably
you have a problem with public inheritance, not necessarily with
private inheritance?
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAFk2RUbVhTEbASYA%2BnAL8h2th6BVbKOP%2BzQOsCnR3M29AZ%3DNtg%40mail.gmail.com.
.
Author: "Arthur O'Dwyer" <arthur.j.odwyer@gmail.com>
Date: Tue, 3 Oct 2017 11:58:31 -0700
Raw View
--f403045c3978d1b53d055aa91360
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
On Tue, Oct 3, 2017 at 11:40 AM, Ville Voutilainen <
ville.voutilainen@gmail.com> wrote:
> On 3 October 2017 at 21:27, Arthur O'Dwyer <arthur.j.odwyer@gmail.com>
> wrote:
> > (5) I still believe that it is a sin to subclass std::error_code,
> > std::exception_ptr, or any other std:: class type that is not already
> part
> > of a classical hierarchy. Composition/aggregation is okay. Inheritance =
is
> > not. You will get slicing and you will get bugs.
>
> Fascinating. I didn't realize the writings that people usually use to
> define what is a sin
> talk about C++. I must update my understanding. :) With that
> digression aside, presumably
> you have a problem with public inheritance, not necessarily with
> private inheritance?
>
Well, personally I would also avoid private inheritance; but yes, public
inheritance is the much bigger problem for things like slicing.
In Niall's case, he's checking std::is_base_of, which will report true even
for private inheritance <https://stackoverflow.com/a/2911185/1424877>, even
though *I assume* the things he's going to try to do with the "E" type will
eventually require public inheritance (e.g. convertibility).
I wish there were a standard type-trait for checking the "public
unambiguous base" relationship, because I strongly believe that that's the
relationship most programmers really care about. Being an inaccessible (
*usually* synonymous with non-public) or ambiguous base class is not a
relationship that I *usually* care about.
https://wandbox.org/permlink/jzjqQAHhpvPnReCM
=E2=80=93Arthur
--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CADvuK0JO-B0PiRhCU27sL_kxE3f%3D-uaOJ5PbstjSpB%2B=
MiuUZ2A%40mail.gmail.com.
--f403045c3978d1b53d055aa91360
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Tue, Oct 3, 2017 at 11:40 AM, Ville Voutilainen <span d=
ir=3D"ltr"><<a href=3D"mailto:ville.voutilainen@gmail.com" target=3D"_bl=
ank">ville.voutilainen@gmail.com</a>></span> wrote:<br><div class=3D"gma=
il_extra"><div class=3D"gmail_quote"><blockquote class=3D"gmail_quote" styl=
e=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(2=
04,204,204);border-left-style:solid;padding-left:1ex"><span class=3D"gmail-=
">On 3 October 2017 at 21:27, Arthur O'Dwyer <<a href=3D"mailto:arth=
ur.j.odwyer@gmail.com">arthur.j.odwyer@gmail.com</a>> wrote:<br>
> (5) I still believe that it is a sin to subclass std::error_code,<br>
> std::exception_ptr, or any other std:: class type that is not already =
part<br>
> of a classical hierarchy. Composition/aggregation is okay. Inheritance=
is<br>
> not. You will get slicing and you will get bugs.<br>
<br>
</span>Fascinating. I didn't realize the writings that people usually u=
se to<br>
define what is a sin<br>
talk about C++. I must update my understanding. :) With that<br>
digression aside, presumably<br>
you have a problem with public inheritance, not necessarily with<br>
private inheritance?<span class=3D"gmail-"><br></span></blockquote><div><br=
></div><div>Well, personally I would also avoid private inheritance; but ye=
s, public inheritance is the much bigger problem for things like slicing.</=
div><div><br></div><div>In Niall's case, he's checking std::is_base=
_of, which <a href=3D"https://stackoverflow.com/a/2911185/1424877">will rep=
ort true even for private inheritance</a>, even though <i>I assume</i> the =
things he's going to try to do with the "E" type will eventua=
lly require public inheritance (e.g. convertibility).</div><div><br></div><=
div>I wish there were a standard type-trait for checking the "public u=
nambiguous base" relationship, because I strongly believe that that=
9;s the relationship most programmers really care about. Being an inaccessi=
ble (<i>usually</i>=C2=A0synonymous with non-public) or ambiguous base clas=
s is not a relationship that I <i>usually</i> care about.=C2=A0</div><div><=
a href=3D"https://wandbox.org/permlink/jzjqQAHhpvPnReCM">https://wandbox.or=
g/permlink/jzjqQAHhpvPnReCM</a><br></div><div><br></div><div>=E2=80=93Arthu=
r</div></div></div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CADvuK0JO-B0PiRhCU27sL_kxE3f%3D-uaOJ5=
PbstjSpB%2BMiuUZ2A%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter"=
>https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CADvuK0JO-B0P=
iRhCU27sL_kxE3f%3D-uaOJ5PbstjSpB%2BMiuUZ2A%40mail.gmail.com</a>.<br />
--f403045c3978d1b53d055aa91360--
.
Author: Ville Voutilainen <ville.voutilainen@gmail.com>
Date: Tue, 3 Oct 2017 22:07:18 +0300
Raw View
On 3 October 2017 at 21:58, Arthur O'Dwyer <arthur.j.odwyer@gmail.com> wrote:
> I wish there were a standard type-trait for checking the "public unambiguous
> base" relationship, because I strongly believe that that's the relationship
> most programmers really care about. Being an inaccessible (usually
> synonymous with non-public) or ambiguous base class is not a relationship
> that I usually care about.
> https://wandbox.org/permlink/jzjqQAHhpvPnReCM
An alternative take is
template<class T, class U>
struct is_public_unambiguous_base_of :
std::conjunction<std::is_class<T>, std::is_class<U>,
std::is_convertible<U*, T*>> {};
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CAFk2RUZuz6vg8o3vi%2BknBtfOf65Qwkfk%3DQCs%2Bw8hYqVQBySJdw%40mail.gmail.com.
.
Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Tue, 03 Oct 2017 21:30:24 +0200
Raw View
On 10/03/2017 08:27 PM, Arthur O'Dwyer wrote:
> (1) A default-constructed std::error_code is absolutely an "ok, no
> error" value. In fact, for any enumeration type E where
> is_error_code_enum_v<E>, the value static_cast<E>(0) must be the "ok,
> no error" value.
Wait, std::error_code and the enumeration E are different things.
std::error_code stores an "int", produced from E via make_error_code(),
which could (conceivably) map E's values to something else.
> I think we are all in agreement that the Standard
> strongly implies that stuff breaks if you deviate from this informal
> rule. Niall referred to the absence of normative wording as "really a
> defect." Yes it is. I would like us all to assume that the defect
> will be fixed, and waste no further verbiage on pedantry in that
> area.
Fine with me.
> (2) Re a tricky idea Jens suggested: `make_error_code(E)` should not
> do any value-munging "tricks" (such as remapping E(200) to int(0), or
> E(0) to int(200)), because such tricks would should be undone by
> `static_cast<E>(ec.code())`, and those semantics are 100% nailed down
> by the Standard.
It's "ec.value()" apparently; and where does it say something about
the static_cast being meaningful (a section / paragraph reference
would help)?
> (5) I still believe that it is a sin to subclass std::error_code,
> std::exception_ptr, or any other std:: class type that is not already
> part of a classical hierarchy. Composition/aggregation is okay.
> Inheritance is not. You will get slicing and you will get bugs.
Agreed.
=20
> (6) Jens's example use-case #4 almost convinced me that
> implicit-construction-from-the-E-type is desirable. `if (!cwd) return
> cwd.error()` is easier on the eyes than `if (!cwd) return
> make_unexpected(cwd.error())`. However, I wonder whether we could get
> the best of both worlds by providing a convenience member function:
> `if (!cwd) return cwd.unexpected()`.
I should probably say here that I find the name "unexpected"
(or "expected", for that matter) particularly unhelpful.
In my world, there's nothing unexpected about an error,
and the discussion about similarities vs. std::variant
seems to indicate that T and E are sometimes viewed as being
on the same level (they're not; E is still an error).
> For the long-term problems
> caused by implicit conversions involving vocabulary types, please see
> the ongoing fiasco of std::string, std::string_view,
> std::filesystem::path. Eliminating implicit conversions from your C++
> code eliminates bugs. Eliminating implicit conversions from your
> proposals eliminates literally YEARS of work for the future members
> of the Committee.
It seems to me that some of that wrapping might cause extra copies
or moves to stick the "E" instance into the wrapper before passing
it to the std::result constructor. Also, I'd be happy to allow
only exact matches for E, i.e. you can only implicitly convert an E
to a std::result<T,E>, not to a std::result<T, E2>, where E converts
to E2. That seems a lot safer than the situation with std::string and
friends.
> (10) Speaking of "levelization", I do like the idea of having
> "higher-level" and "lower-level" headers in the STL. I think it's
> unfortunate that <system_error> =E2=80=94 which sounds like a low-level
> header =E2=80=94 actually depends on <string>, which recursively depends =
on
> most of the STL (<string_view>, <ostream>, et cetera). I talked to
> Charley about this at CppCon: I'm ambivalent. On the one hand I think
> it really sucks that <system_error> has any dependencies at all. On
> the other hand, I appreciate the idea of "vocabulary types," and it
> feels hypocritical to condemn the library's own use of `std::string`
> as the vocabulary type for returning a string.
It seems, since std::result<T,E> is a template, we can stick it into
its own header and only people wanting E =3D std::error_code need to
pull in <system_error> (and its dependencies) themselves. People
wanting E =3D their_own_enum will be fine as-is.
> (11) Niall writes: "Outcome uses struct storage, not union storage."=20
> The paper Jens and I were reading flatly contradicts that statement,
> on page 4, where it says "Result requires the following layout to be
> implemented:" and then shows a piece of code involving a union.
> However, the reference C implementation on page 14 uses a non-union
> struct, and the reference C++ implementation on page 17 uses a
> "non-standard" optional<T> with the caveats listed in a comment at
> the bottom of page 16. It would be much *much* clearer if the new
> paper didn't imply the use of a union/optional/variant; it would save
> Niall a lot of argumentation. If you want a standard-layout struct,
> just use one! Don't even put "union" in your sample code!
There's a union where an "unsigned int" is shared with E; this should
simply go. If you want to show standard-layout, just show
struct result {
T _value;
/* integral or so */ discriminator;
E _error;
};
However, prescribing this order of members might be sub-optimal in
terms of alignment / packing of T and E; some other order might
yield a smaller "result" layout on some platforms for some T and E.
> (12) Niall writes: "E is not necessarily an error for Expected. It's
> merely an 'unexpected'." This is a distinction without a difference.
> Whether we call it an "error", an "unexpected result", or an
> "exceptional state", the point is that it's a "disappointment" (to
> use Lawrence Crowl's term). The user's expectations are that
> foo.value() will give them the normal-path result (if any), and that
> foo.error() will give them the "disappointment-path" result (if any).
> Jens points out, rightly, that if the user asks for foo.error() and
> there is no disappointment to report, it makes some sense to return
> "no error" as opposed to blowing up the program via a thrown
> exception or via undefined behavior. As to the question of whether we
> can generally consider a default-constructed E to indicate "no
> error", please see my point (1) in this email.
I'm not convinced we should restrict E to the set of types Niall
has in his paper; if we have a more general E, it's maybe a harder
sell that a default-constructed E should never actually indicate an
error.
=20
> (13) I don't see the usefulness of outcome<X,Y,Z>; but I know that if
> I don't like it I can avoid using it, and it sounds like Niall is not
> proposing that one for standardization anyway. (That is, he's
> proposing it for Boost.Outcome but not for C++2a.)
There's certainly the issue that just having a std::error_code as E
is not good enough if you also want to propagate some context to
upper layers (e.g. which function failed to create a file using which
pathname). I sympathize, but I still feel allowing something custom
such as
struct my_E {
std::error_code ec;
std::filesystem::path failed_path;
std::string failed_function;
};
is the way to go here. If, on your way out, you need to strip
that info down (maybe after logging) to E =3D std::error_code, you
just pick the relevant member. (I have a feeling that creating
a std::exception_ptr is non-cheap, so requiring people to transport
extra info via that mechanism seems not a good idea.)
As a general remark, error handling seems very much a system-level
design exercise (regardless of whether using exceptions or std::result),
so I fully expect each code base to have an opinion on what E's they
permit or desire.
Further, I'm not of the opinion that the standard should provide
everything to everybody, so slightly burdening someone wanting a my_E
(e.g. with an additional ADL customization point to cater to) is
fine with me.
Jens
--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/59D3E550.9050109%40gmx.net.
.
Author: "Arthur O'Dwyer" <arthur.j.odwyer@gmail.com>
Date: Tue, 3 Oct 2017 13:07:06 -0700
Raw View
--94eb2c1afe8c1fcbc5055aaa0922
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
On Tue, Oct 3, 2017 at 12:30 PM, Jens Maurer <Jens.Maurer@gmx.net> wrote:
> On 10/03/2017 08:27 PM, Arthur O'Dwyer wrote:
> > (1) A default-constructed std::error_code is absolutely an "ok, no
> > error" value. In fact, for any enumeration type E where
> > is_error_code_enum_v<E>, the value static_cast<E>(0) must be the "ok,
> > no error" value.
>
> Wait, std::error_code and the enumeration E are different things.
> std::error_code stores an "int", produced from E via make_error_code(),
> which could (conceivably) map E's values to something else.
>
This was my (2). ;)
> (2) Re a tricky idea Jens suggested: `make_error_code(E)` should not
> > do any value-munging "tricks" (such as remapping E(200) to int(0), or
> > E(0) to int(200)), because such tricks would should be undone by
> > `static_cast<E>(ec.code())`, and those semantics are 100% nailed down
> > by the Standard.
>
> It's "ec.value()" apparently; and where does it say something about
> the static_cast being meaningful (a section / paragraph reference
> would help)?
>
Good catch, I meant .value() not .code(). (".code()" turns a system_error
into an error_code. ".value()" turns an error_code into an int.)
This is the pedantry I don't want to get into, so I won't. (But examine the
specifications for error_code::message() and error_category::message() and
see if you think there's any room for the int values to be different from
the enumeration values. And then remember that we've already agreed this is
a defect and we want to close any loopholes in it, so maybe don't think too
hard about ways to exploit those loopholes in the meantime?)
> (6) Jens's example use-case #4 almost convinced me that
> > implicit-construction-from-the-E-type is desirable. `if (!cwd) return
> > cwd.error()` is easier on the eyes than `if (!cwd) return
> > make_unexpected(cwd.error())`. However, I wonder whether we could get
> > the best of both worlds by providing a convenience member function:
> > `if (!cwd) return cwd.unexpected()`.
>
> I should probably say here that I find the name "unexpected"
> (or "expected", for that matter) particularly unhelpful.
> In my world, there's nothing unexpected about an error,
> and the discussion about similarities vs. std::variant
> seems to indicate that T and E are sometimes viewed as being
> on the same level (they're not; E is still an error).
>
Distinction without difference. "Error", "unexpected", "exceptional", and
"disappointment" are all words for the same thing.
Don't think of T and E as being "on the same level." There's a reason we
say "T and *E*" instead of "T and U" or "T1 and T2".
Expected<T,E> is similar to variant<T,E> in exactly the same way that
optional<T> is similar to variant<T,monostate>.
> > For the long-term problems
> > caused by implicit conversions involving vocabulary types, please see
> > the ongoing fiasco of std::string, std::string_view,
> > std::filesystem::path. Eliminating implicit conversions from your C++
> > code eliminates bugs. Eliminating implicit conversions from your
> > proposals eliminates literally YEARS of work for the future members
> > of the Committee.
>
> It seems to me that some of that wrapping might cause extra copies
> or moves to stick the "E" instance into the wrapper before passing
> it to the std::result constructor. Also, I'd be happy to allow
> only exact matches for E, i.e. you can only implicitly convert an E
> to a std::result<T,E>, not to a std::result<T, E2>, where E converts
> to E2. That seems a lot safer than the situation with std::string and
> friends.
>
std::result<T,E> will be passed from function to function by value. (Unless
you like out-parameters? I should add a 14th point: I hate out-parameters.)
So we assume that both T and E are efficiently move-constructible. "Extra
copies" aren't a problem.
Also, I'm not suggesting any kind of new "wrapper" *type*; I'm just
suggesting that conversions between the existing types be *explicit*
instead of happening implicitly.
The Expected proposal includes a wrapper type std::unexpected<E>, but it's
exactly as lightweight as E itself, and has move semantics, so there are no
extra copies happening.
> (10) Speaking of "levelization", I do like the idea of having
> > "higher-level" and "lower-level" headers in the STL. I think it's
> > unfortunate that <system_error> =E2=80=94 which sounds like a low-level
> > header =E2=80=94 actually depends on <string>, which recursively depend=
s on
> > most of the STL (<string_view>, <ostream>, et cetera). I talked to
> > Charley about this at CppCon: I'm ambivalent. On the one hand I think
> > it really sucks that <system_error> has any dependencies at all. On
> > the other hand, I appreciate the idea of "vocabulary types," and it
> > feels hypocritical to condemn the library's own use of `std::string`
> > as the vocabulary type for returning a string.
>
> It seems, since std::result<T,E> is a template, we can stick it into
> its own header and only people wanting E =3D std::error_code need to
> pull in <system_error> (and its dependencies) themselves. People
> wanting E =3D their_own_enum will be fine as-is.
>
I agree with your general gist here, but specifically in this case I think
Niall wants std::error_code to be used in the default template arguments of
std::result. So for example we could write the source code
#include <result> // for std::result
int main() { std::result<int> x; auto y =3D x.error().message(); }
and expect that it would compile
<https://bugs.llvm.org/show_bug.cgi?id=3D34529>.
Header inclusion in the C++ library is a mess, though. I don't expect us to
"solve" it in this thread. :)
> > (12) Niall writes: "E is not necessarily an error for Expected. It's
> > merely an 'unexpected'." This is a distinction without a difference.
> > Whether we call it an "error", an "unexpected result", or an
> > "exceptional state", the point is that it's a "disappointment" (to
> > use Lawrence Crowl's term). The user's expectations are that
> > foo.value() will give them the normal-path result (if any), and that
> > foo.error() will give them the "disappointment-path" result (if any).
> > Jens points out, rightly, that if the user asks for foo.error() and
> > there is no disappointment to report, it makes some sense to return
> > "no error" as opposed to blowing up the program via a thrown
> > exception or via undefined behavior. As to the question of whether we
> > can generally consider a default-constructed E to indicate "no
> > error", please see my point (1) in this email.
>
> I'm not convinced we should restrict E to the set of types Niall
> has in his paper; if we have a more general E, it's maybe a harder
> sell that a default-constructed E should never actually indicate an
> error.
>
I am happy with Niall's logic earlier in this thread that the library's job
is to give the user a clear way to *not* shoot themselves in the foot. If
some user chooses to do something dumb like set E =3D std::mutex or whateve=
r,
then the library does not need to coddle that particular user.
I am also happy to restrict the set of allowable E's right now and relax it
later. However, I certainly don't like Niall's particular choice of
restriction; I wouldn't involve is_base_of at all. Letting E =3D std::stri=
ng
seems plausible, for example. (And std::string is cheaply
move-constructible.)
=E2=80=93Arthur
--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/CADvuK0KxuoR2h_XFy6UgPz%2B3ewPumxAk4Da_w181NZDJp=
D_GTw%40mail.gmail.com.
--94eb2c1afe8c1fcbc5055aaa0922
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr">On Tue, Oct 3, 2017 at 12:30 PM, Jens Maurer <span dir=3D"=
ltr"><<a href=3D"mailto:Jens.Maurer@gmx.net" target=3D"_blank">Jens.Maur=
er@gmx.net</a>></span> wrote:<br><div class=3D"gmail_extra"><div class=
=3D"gmail_quote"><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px =
0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-l=
eft-style:solid;padding-left:1ex"><span class=3D"gmail-">On 10/03/2017 08:2=
7 PM, Arthur O'Dwyer wrote:<br>
> (1) A default-constructed std::error_code is absolutely an "ok, n=
o<br>
> error" value. In fact, for any enumeration type E where<br>
> is_error_code_enum_v<E>, the value static_cast<E>(0) must =
be the "ok,<br>
> no error" value.<br>
<br>
</span>Wait, std::error_code and the enumeration E are different things.<br=
>
std::error_code stores an "int", produced from E via make_error_c=
ode(),<br>
which could (conceivably) map E's values to something else.<br></blockq=
uote><div><br></div><div>This was my (2). ;)</div><div><br></div><blockquot=
e class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left-width=
:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-lef=
t:1ex"><span class=3D"gmail-">
> (2) Re a tricky idea Jens suggested: `make_error_code(E)` should not<b=
r>
> do any value-munging "tricks" (such as remapping E(200) to i=
nt(0), or<br>
> E(0) to int(200)), because such tricks would should be undone by<br>
> `static_cast<E>(ec.code())`, and those semantics are 100% nailed=
down<br>
> by the Standard.<br>
<br>
</span>It's "ec.value()" apparently; and where does it say so=
mething about<br>
the static_cast being meaningful (a section / paragraph reference<br>
would help)?<br></blockquote><div><br></div><div>Good catch, I meant .value=
() not .code(). =C2=A0(".code()" turns a system_error into an err=
or_code. ".value()" turns an error_code into an int.)</div><div>T=
his is the pedantry I don't want to get into, so I won't. (But exam=
ine the specifications for error_code::message() and error_category::messag=
e() and see if you think there's any room for the int values to be diff=
erent from the enumeration values. And then remember that we've already=
agreed this is a defect and we want to close any loopholes in it, so maybe=
don't think too hard about ways to exploit those loopholes in the mean=
time?)</div><div><br></div><div><br></div><blockquote class=3D"gmail_quote"=
style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:=
rgb(204,204,204);border-left-style:solid;padding-left:1ex"><span class=3D"g=
mail-">> (6) Jens's example use-case #4 almost convinced me that<br>
> implicit-construction-from-<wbr>the-E-type is desirable. `if (!cwd) re=
turn<br>
> cwd.error()` is easier on the eyes than `if (!cwd) return<br>
> make_unexpected(cwd.error())`. However, I wonder whether we could get<=
br>
> the best of both worlds by providing a convenience member function:<br=
>
> `if (!cwd) return cwd.unexpected()`.<br>
<br>
</span>I should probably say here that I find the name "unexpected&quo=
t;<br>
(or "expected", for that matter) particularly unhelpful.<br>
In my world, there's nothing unexpected about an error,<br>
and the discussion about similarities vs. std::variant<br>
seems to indicate that T and E are sometimes viewed as being<br>
on the same level (they're not; E is still an error).<br></blockquote><=
div><br></div><div>Distinction without difference. "Error", "=
;unexpected", "exceptional", and "disappointment" =
are all words for the same thing.</div><div><br></div><div>Don't think =
of T and E as being "on the same level." There's a reason we =
say "T and <b>E</b>" instead of "T and U" or "T1 a=
nd T2".</div><div>Expected<T,E> is similar to variant<T,E>=
in exactly the same way that optional<T> is similar to variant<T,=
monostate>.</div><div><br></div><div>=C2=A0</div><blockquote class=3D"gm=
ail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left-width:1px;border-l=
eft-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><span =
class=3D"gmail-">>=C2=A0 =C2=A0For the long-term problems<br>
> caused by implicit conversions involving vocabulary types, please see<=
br>
> the ongoing fiasco of std::string, std::string_view,<br>
> std::filesystem::path. Eliminating implicit conversions from your C++<=
br>
> code eliminates bugs. Eliminating implicit conversions from your<br>
> proposals eliminates literally YEARS of work for the future members<br=
>
> of the Committee.<br>
<br>
</span>It seems to me that some of that wrapping might cause extra copies<b=
r>
or moves to stick the "E" instance into the wrapper before passin=
g<br>
it to the std::result constructor.=C2=A0 Also, I'd be happy to allow<br=
>
only exact matches for E, i.e. you can only implicitly convert an E<br>
to a std::result<T,E>, not to a std::result<T, E2>, where E con=
verts<br>
to E2.=C2=A0 That seems a lot safer than the situation with std::string and=
<br>
friends.<br></blockquote><div><br></div><div>std::result<T,E> will be=
passed from function to function by value. (Unless you like out-parameters=
? I should add a 14th point: I hate out-parameters.) =C2=A0So we assume tha=
t both T and E are efficiently move-constructible. "Extra copies"=
aren't a problem.</div><div>Also, I'm not suggesting any kind of n=
ew "wrapper" <i>type</i>; I'm just suggesting that conversion=
s between the existing types be <i>explicit</i> instead of happening implic=
itly.</div><div>The Expected proposal includes a wrapper type std::unexpect=
ed<E>, but it's exactly as lightweight as E itself, and has move =
semantics, so there are no extra copies happening.</div><div><br></div><div=
><br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.=
8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-st=
yle:solid;padding-left:1ex"><span class=3D"gmail-">> (10) Speaking of &q=
uot;levelization", I do like the idea of having<br>
> "higher-level" and "lower-level" headers in the ST=
L. I think it's<br>
> unfortunate that <system_error> =E2=80=94 which sounds like a lo=
w-level<br>
> header =E2=80=94 actually depends on <string>, which recursively=
depends on<br>
> most of the STL (<string_view>, <ostream>, et cetera). I t=
alked to<br>
> Charley about this at CppCon: I'm ambivalent. On the one hand I th=
ink<br>
> it really sucks that <system_error> has any dependencies at all.=
On<br>
> the other hand, I appreciate the idea of "vocabulary types,"=
and it<br>
> feels hypocritical to condemn the library's own use of `std::strin=
g`<br>
> as the vocabulary type for returning a string.<br>
<br>
</span>It seems, since std::result<T,E> is a template, we can stick i=
t into<br>
its own header and only people wanting E =3D std::error_code need to<br>
pull in <system_error> (and its dependencies) themselves.=C2=A0 Peopl=
e<br>
wanting E =3D their_own_enum will be fine as-is.<br></blockquote><div><br><=
/div><div>I agree with your general gist here, but specifically in this cas=
e I think Niall wants std::error_code to be used in the default template ar=
guments of std::result. So for example we could write the source code</div>=
<div><br></div><div>#include <result> =C2=A0// for std::result</div><=
div>int main() { std::result<int> x; auto y =3D x.error().message(); =
}</div><div><br></div><div>and <a href=3D"https://bugs.llvm.org/show_bug.cg=
i?id=3D34529">expect that it would compile</a>.</div><div>Header inclusion =
in the C++ library is a mess, though. I don't expect us to "solve&=
quot; it in this thread. :)</div><div><br></div><div><br></div><div>=C2=A0<=
/div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;bo=
rder-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:so=
lid;padding-left:1ex"><span class=3D"gmail-">> (12) Niall writes: "=
E is not necessarily an error for Expected. It's<br>
> merely an 'unexpected'." This is a distinction without a =
difference.<br>
> Whether we call it an "error", an "unexpected result&qu=
ot;, or an<br>
> "exceptional state", the point is that it's a "disa=
ppointment" (to<br>
> use Lawrence Crowl's term). The user's expectations are that<b=
r>
> foo.value() will give them the normal-path result (if any), and that<b=
r>
> foo.error() will give them the "disappointment-path" result =
(if any).<br>
> Jens points out, rightly, that if the user asks for foo.error() and<br=
>
> there is no disappointment to report, it makes some sense to return<br=
>
> "no error" as opposed to blowing up the program via a thrown=
<br>
> exception or via undefined behavior. As to the question of whether we<=
br>
> can generally consider a default-constructed E to indicate "no<br=
>
> error", please see my point (1) in this email.<br>
<br>
</span>I'm not convinced we should restrict E to the set of types Niall=
<br>
has in his paper; if we have a more general E, it's maybe a harder<br>
sell that a default-constructed E should never actually indicate an<br>
error.<br></blockquote><div><br></div><div>I am happy with Niall's logi=
c earlier in this thread that the library's job is to give the user a c=
lear way to <i>not</i> shoot themselves in the foot. If some user chooses t=
o do something dumb like set <font face=3D"monospace, monospace">E =3D std:=
:mutex</font> or whatever, then the library does not need to coddle that pa=
rticular user.</div><div>I am also happy to restrict the set of allowable E=
's right now and relax it later. However, I certainly don't like Ni=
all's particular choice of restriction; I wouldn't involve is_base_=
of at all.=C2=A0 Letting <font face=3D"monospace, monospace">E =3D std::str=
ing</font> seems plausible, for example. (And std::string is cheaply move-c=
onstructible.)</div><div><br></div><div>=E2=80=93Arthur</div></div></div></=
div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/CADvuK0KxuoR2h_XFy6UgPz%2B3ewPumxAk4D=
a_w181NZDJpD_GTw%40mail.gmail.com?utm_medium=3Demail&utm_source=3Dfooter">h=
ttps://groups.google.com/a/isocpp.org/d/msgid/std-proposals/CADvuK0KxuoR2h_=
XFy6UgPz%2B3ewPumxAk4Da_w181NZDJpD_GTw%40mail.gmail.com</a>.<br />
--94eb2c1afe8c1fcbc5055aaa0922--
.
Author: Jens Maurer <Jens.Maurer@gmx.net>
Date: Tue, 03 Oct 2017 22:27:36 +0200
Raw View
On 10/03/2017 10:07 PM, Arthur O'Dwyer wrote:
> On Tue, Oct 3, 2017 at 12:30 PM, Jens Maurer <Jens.Maurer@gmx.net <mailto=
:Jens.Maurer@gmx.net>> wrote:
>=20
> On 10/03/2017 08:27 PM, Arthur O'Dwyer wrote:
> > (6) Jens's example use-case #4 almost convinced me that
> > implicit-construction-from-the-E-type is desirable. `if (!cwd) retu=
rn
> > cwd.error()` is easier on the eyes than `if (!cwd) return
> > make_unexpected(cwd.error())`. However, I wonder whether we could g=
et
> > the best of both worlds by providing a convenience member function:
> > `if (!cwd) return cwd.unexpected()`.
>=20
> I should probably say here that I find the name "unexpected"
> (or "expected", for that matter) particularly unhelpful.
> In my world, there's nothing unexpected about an error,
> and the discussion about similarities vs. std::variant
> seems to indicate that T and E are sometimes viewed as being
> on the same level (they're not; E is still an error).
>=20
>=20
> Distinction without difference. "Error", "unexpected", "exceptional", and=
"disappointment" are all words for the same thing.
Right, but it seems I have to write one of these words over
and over again in my future code, so from that angle, I care.
> std::result<T,E> will be passed from function to function by value. (Unle=
ss you like out-parameters? I should add a 14th point: I hate out-parameter=
s.) So we assume that both T and E are efficiently move-constructible. "Ex=
tra copies" aren't a problem.
> Also, I'm not suggesting any kind of new "wrapper" /type/; I'm just sugge=
sting that conversions between the existing types be /explicit/ instead of =
happening implicitly.
> The Expected proposal includes a wrapper type std::unexpected<E>, but it'=
s exactly as lightweight as E itself, and has move semantics, so there are =
no extra copies happening.
Not all moves are cheap. std::array<int, 1024> is not cheap to move.
> I am happy with Niall's logic earlier in this thread that the library's j=
ob is to give the user a clear way to /not/ shoot themselves in the foot. I=
f some user chooses to do something dumb like set E =3D std::mutex or whate=
ver, then the library does not need to coddle that particular user.
> I am also happy to restrict the set of allowable E's right now and relax =
it later. However, I certainly don't like Niall's particular choice of rest=
riction; I wouldn't involve is_base_of at all. Letting E =3D std::string s=
eems plausible, for example. (And std::string is cheaply move-constructible=
..)
I don't think we should get into the business of trying to
enumerate the plausible E's here; this would be a large time-sink
for no good reason. (Prescribing some properties of E such as
"default constructible" is fine, though.)
Jens
--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/59D3F2B8.6060404%40gmx.net.
.
Author: Niall Douglas <nialldouglas14@gmail.com>
Date: Tue, 3 Oct 2017 14:08:04 -0700 (PDT)
Raw View
------=_Part_7387_381150017.1507064884540
Content-Type: multipart/alternative;
boundary="----=_Part_7388_1166136683.1507064884541"
------=_Part_7388_1166136683.1507064884541
Content-Type: text/plain; charset="UTF-8"
>
>
> Now, it's obviously hard to argue about C compatibility for
> something that is a template and has a plethora of interesting
> constructors. However, we already attempt something like
> that for std::complex; see 29.5 p4 [complex.numbers].
>
> Maybe we want to say something like std::result and a struct X
> consisting of T, unsigned int, and E members have a common
> initial sequence that is all of X.
>
> The way I phrased it is that Outcome propagates standard layoutness of T
and E. So if both T and E are standard layout, result<T, E> will also be
standard layout and and it will be this C struct X here.
Niall
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/a86e07d0-c3b1-430e-b725-2a281f4a862f%40isocpp.org.
------=_Part_7388_1166136683.1507064884541
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><blockquote class=3D"gmail_quote" style=3D"margin: 0;margi=
n-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><br>Now, it&#=
39;s obviously hard to argue about C compatibility for
<br>something that is a template and has a plethora of interesting
<br>constructors. =C2=A0However, we already attempt something like
<br>that for std::complex; see 29.5 p4 [complex.numbers].
<br>
<br>Maybe we want to say something like std::result and a struct X
<br>consisting of T, unsigned int, and E members have a common
<br>initial sequence that is all of X.
<br>
<br></blockquote><div>The way I phrased it is that Outcome propagates stand=
ard layoutness of T and E. So if both T and E are standard layout, result&l=
t;T, E> will also be standard layout and and it will be this C struct X =
here.</div><div><br></div><div>Niall</div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/a86e07d0-c3b1-430e-b725-2a281f4a862f%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/a86e07d0-c3b1-430e-b725-2a281f4a862f=
%40isocpp.org</a>.<br />
------=_Part_7388_1166136683.1507064884541--
------=_Part_7387_381150017.1507064884540--
.
Author: Niall Douglas <nialldouglas14@gmail.com>
Date: Tue, 3 Oct 2017 14:33:23 -0700 (PDT)
Raw View
------=_Part_7378_495309180.1507066403242
Content-Type: multipart/alternative;
boundary="----=_Part_7379_2015959300.1507066403242"
------=_Part_7379_2015959300.1507066403242
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
>
>
> (3) It seems very important to Niall that the Expected/Result type that i=
s=20
> standardized should have a normatively defined class definition, so that=
=20
> anyone could look at the Standard wording and deduce exactly how to=20
> interoperate with Expected/Result from C code or from pre-C++2a code. I=
=20
> sympathize with this idea. I think Nicol was right when he said that the=
=20
> C++ Standard generally does *not* standardize class definitions. So just =
be=20
> aware that you will be swimming upstream to get this =E2=80=94 especially=
if you=20
> want a non-standard-layout class with special member functions, private=
=20
> members, etc etc. Jens gives the example of std::complex.
>
All I request is that standard layout-ness is preserved. So if T and E are=
=20
both standard layout, then so must be result<T, E>.
Outcome v2 already implements this guarantee.
=20
>
> (5) I still believe that it is a sin to subclass std::error_code,=20
> std::exception_ptr, or any other std:: class type that is not already par=
t=20
> of a classical hierarchy. Composition/aggregation is okay. Inheritance is=
=20
> not. You will get slicing and you will get bugs.
>
I think it's entirely fair that if an end user controls his entire program=
=20
world that he can create his own local error_code subclassed from=20
std::error_code with added payload. Ditto for exception_ptr.
Sure, private inheritance would be better, but that's up to the end user.
For the record, Outcome v1's error_code_extended was safe to slice. You=20
lost the payload, but it was safe.
=20
>
> (6) Jens's example use-case #4 almost convinced me that=20
> implicit-construction-from-the-E-type is desirable. `if (!cwd) return=20
> cwd.error()` is easier on the eyes than `if (!cwd) return=20
> make_unexpected(cwd.error())`. However, I wonder whether we could get the=
=20
> best of both worlds by providing a convenience member function: `if (!cwd=
)=20
> return cwd.unexpected()`. For the long-term problems caused by implicit=
=20
> conversions involving vocabulary types, please see the ongoing fiasco of=
=20
> std::string, std::string_view, std::filesystem::path. Eliminating implici=
t=20
> conversions from your C++ code eliminates bugs. Eliminating implicit=20
> conversions from your proposals eliminates literally YEARS of work for th=
e=20
> future members of the Committee.
>
I believe D0323R3 just removed the expected.get_unexpected() just this=20
revision. And make_unexpected was removed in Toronto incidentally, along=20
with all the make_* functions. They're all gone now.
See https://github.com/viboes/std-make/blob/master/doc/proposal/expected/d0=
323r3.md
=20
>
> (8) I certainly hope that both Result<T,E> and Expected<T,E> are "X"=20
> whenever both T and E are "X", for values of "X" including at least=20
> "trivially copyable" and "trivially destructible". If some implementation=
=20
> of Result or Expected does not provide those guarantees, then that's a Qo=
I=20
> issue against that implementation. (I hope that the version that gets=20
> standardized will have normative wording *requiring* those guarantees. If=
=20
> that happens, then implementations without those guarantees will be=20
> non-conforming.)
>
Both Outcome and Expected preserve triviality in copy, move, assignment and=
=20
destruction. Both provide strong never empty guarantees. Currently only=20
Outcome preserves standard layout-ness, but Vicente is open to Expected=20
also doing so if Albuquerque likes the idea.
=20
> =20
> (9) Niall wrote: "If you are adding a feature which uses 98% of an=20
> existing feature, then the standard should require use of that existing=
=20
> feature." I strongly disagree with that statement. Now, I *do* think (an=
d=20
> I think Niall might agree) that we should not add new features with small=
=20
> gratuitous quirks that make them impossible to implement in terms of othe=
r=20
> standard features. To take two examples of the "gratuitous quirk" problem=
:=20
> std::packaged_task<R(A...)> is not implementable in terms of=20
> std::function<R(A...)> because copyability, and std::vector<T,A>::resize =
is=20
> not implementable in terms of std::uninitialized_move_if_noexcept() becau=
se=20
> allocator_traits. Therefore, if it were truly *impossible* to implement=
=20
> Expected<T,E> in terms of std::variant<T,E>, I'd complain.
> HOWEVER, I repeat that no sane implementation should pull in <variant> as=
=20
> a result of including <expected>. The former is a "higher-level" feature=
=20
> than the latter; it includes a ton of TMP machinery that is not needed by=
=20
> <expected>. I might expect both headers to include some "helper" header=
=20
> providing just the common parts needed by both.
>
This is *exactly* what I want to see: <basic_variant>
=20
> We see an example of this in both libstdc++ and libc++, where <set> and=
=20
> <map> are implemented in terms of a "helper" header sometimes named=20
> <__tree>. It is theoretically possible to implement std::map<K,V> in ter=
ms=20
> of std::set<something_clever<K,V>>, but no sane implementation will pull =
in=20
> all of <set> as a result of including <map>.
> I hope this clarifies my position.
>
Dinkumware's STL is also full of common internal implementation classes=20
shared by the public ones.
What bugs me severely is that frequently I am writing code which needs a=20
*subset* of a STL container, and lo and behold haven't all three major STL=
=20
implementations found the exact same problem and have internal classes=20
implementing *exactly* what I need.
Those internal classes should be standardised into C++! Those internal=20
classes are often a damn sight more useful than the official STL classes,=
=20
but they're usually made private costing me and countless others effort in=
=20
reinventing a wheel reinvented many times already.
=20
>
> (10) Speaking of "levelization", I do like the idea of having=20
> "higher-level" and "lower-level" headers in the STL. I think it's=20
> unfortunate that <system_error> =E2=80=94 which sounds like a low-level h=
eader =E2=80=94=20
> actually depends on <string>, which recursively depends on most of the ST=
L=20
> (<string_view>, <ostream>, et cetera). I talked to Charley about this at=
=20
> CppCon: I'm ambivalent. On the one hand I think it really sucks that=20
> <system_error> has any dependencies at all. On the other hand, I apprecia=
te=20
> the idea of "vocabulary types," and it feels hypocritical to condemn the=
=20
> library's own use of `std::string` as the vocabulary type for returning a=
=20
> string.
>
The reason it depends on string is that Beman felt that message strings=20
would be generally programmatically, and therefore need memory allocation=
=20
and freeing once done.
And indeed on Windows they are generated programmatically, localised to the=
=20
current user language.
=20
>
> (11) Niall writes: "Outcome uses struct storage, not union storage."
> The paper Jens and I were reading flatly contradicts that statement, on=
=20
> page 4, where it says "Result requires the following layout to be=20
> implemented:" and then shows a piece of code involving a union. However,=
=20
> the reference C implementation
> on page 14 uses a non-union struct, and the reference C++ implementation=
=20
> on page 17 uses a "non-standard" optional<T> with the caveats listed in a=
=20
> comment at the bottom of page 16. It would be much *much* clearer if the=
=20
> new paper didn't imply the use of a union/optional/variant; it would save=
=20
> Niall a lot of argumentation. If you want a standard-layout struct, just=
=20
> use one! Don't even put "union" in your sample code!
>
Others also found draft 1 confusing. Outcome v2 has always used struct=20
storage, it was a recommendation by the peer review. I've uploaded an=20
interim draft 2 paper on another thread to hopefully clarify this problem.
=20
>
> (12) Niall writes: "E is not necessarily an error for Expected. It's=20
> merely an 'unexpected'." This is a distinction without a difference.=20
> Whether we call it an "error", an "unexpected result", or an "exceptional=
=20
> state", the point is that it's a "disappointment" (to use Lawrence Crowl'=
s=20
> term). The user's expectations are that foo.value() will give them the=20
> normal-path result (if any), and that foo.error() will give them the=20
> "disappointment-path" result (if any). Jens points out, rightly, that if=
=20
> the user asks for foo.error() and there is no disappointment to report, i=
t=20
> makes some sense to return "no error" as opposed to blowing up the progra=
m=20
> via a thrown exception or via undefined behavior. As to the question of=
=20
> whether we can generally consider a default-constructed E to indicate "no=
=20
> error", please see my point (1) in this email.
>
I thought Jens was making a stronger point than this actually. He seemed to=
=20
feel that these objects aren't returning disappointment, they are returning=
=20
an *error*. That's a much stronger meaning than *failure*, let alone=20
disappointment.
And I'm fairly much in agreement on that. Draft 2 paper tries to get into=
=20
the importance of starting your design with a clearly defined mission and=
=20
use case. Lots of "tricky" decisions fall into place if everyone is onboard=
=20
regarding what problem we are solving.
=20
>
> (13) I don't see the usefulness of outcome<X,Y,Z>; but I know that if I=
=20
> don't like it I can avoid using it, and it sounds like Niall is not=20
> proposing that one for standardization anyway. (That is, he's proposing i=
t=20
> for Boost.Outcome but not for C++2a.)
>
=20
outcome<T, EC, E|P> is definitely a Boost-ism. As are the policy classes,=
=20
ADL injection points, and all that other stuff Boost folk love. I only=20
mentioned it to demonstrate there are design layers of increasing=20
complexity in Outcome, that's all. A subset of those might be better to=20
standardise than one single object design to rule them all.
Niall
--=20
You received this message because you are subscribed to the Google Groups "=
ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp=
..org/d/msgid/std-proposals/7e4b7d7d-a3ae-42c0-930b-f53131f1d7c2%40isocpp.or=
g.
------=_Part_7379_2015959300.1507066403242
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><blockquote class=3D"gmail_quote" style=3D"margin: 0;margi=
n-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"l=
tr"><div><br></div><div>(3) It seems very important to Niall that the Expec=
ted/Result type that is standardized should have a normatively defined clas=
s definition, so that anyone could look at the Standard wording and deduce =
exactly how to interoperate with Expected/Result from C code or from pre-C+=
+2a code. I sympathize with this idea. I think Nicol was right when he said=
that the C++ Standard generally does *not* standardize class definitions. =
So just be aware that you will be swimming upstream to get this =E2=80=94 e=
specially if you want a non-standard-layout class with special member funct=
ions, private members, etc etc. Jens gives the example of std::complex.</di=
v></div></blockquote><div><br></div><div>All I request is that standard lay=
out-ness is preserved. So if T and E are both standard layout, then so must=
be result<T, E>.</div><div><br></div><div>Outcome v2 already impleme=
nts this guarantee.</div><div>=C2=A0</div><blockquote class=3D"gmail_quote"=
style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-=
left: 1ex;"><div dir=3D"ltr"><div><br></div><div>(5) I still believe that i=
t is a sin to subclass std::error_code, std::exception_ptr, or any other st=
d:: class type that is not already part of a classical hierarchy. Compositi=
on/aggregation is okay. Inheritance is not. You will get slicing and you wi=
ll get bugs.</div></div></blockquote><div><br></div><div>I think it's e=
ntirely fair that if an end user controls his entire program world that he =
can create his own local error_code subclassed from std::error_code with ad=
ded payload. Ditto for exception_ptr.</div><div><br></div><div>Sure, privat=
e inheritance would be better, but that's up to the end user.</div><div=
><br></div><div>For the record, Outcome v1's error_code_extended was sa=
fe to slice. You lost the payload, but it was safe.</div><div>=C2=A0</div><=
blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bord=
er-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><br></div=
><div>(6) Jens's example use-case #4 almost convinced me that implicit-=
construction-from-<wbr>the-E-type is desirable. `if (!cwd) return cwd.error=
()` is easier on the eyes than `if (!cwd) return make_unexpected(cwd.error(=
))`. However, I wonder whether we could get the best of both worlds by prov=
iding a convenience member function: `if (!cwd) return cwd.unexpected()`. F=
or the long-term problems caused by implicit conversions involving vocabula=
ry types, please see the ongoing fiasco of std::string, std::string_view, s=
td::filesystem::path. Eliminating implicit conversions from your C++ code e=
liminates bugs. Eliminating implicit conversions from your proposals elimin=
ates literally YEARS of work for the future members of the Committee.</div>=
</div></blockquote><div><br></div><div>I believe D0323R3 just removed the e=
xpected.get_unexpected() just this revision. And make_unexpected was remove=
d in Toronto incidentally, along with all the make_* functions. They're=
all gone now.</div><div><br></div><div>See=C2=A0https://github.com/viboes/=
std-make/blob/master/doc/proposal/expected/d0323r3.md</div><div>=C2=A0</div=
><blockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;bo=
rder-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><br></d=
iv><div>(8) I certainly hope that both Result<T,E> and Expected<T,=
E> are "X" whenever both T and E are "X", for values=
of "X" including at least "trivially copyable" and &qu=
ot;trivially destructible". If some implementation of Result or Expect=
ed does not provide those guarantees, then that's a QoI issue against t=
hat implementation. (I hope that the version that gets standardized will ha=
ve normative wording *requiring* those guarantees. If that happens, then im=
plementations without those guarantees will be non-conforming.)</div></div>=
</blockquote><div><br></div><div>Both Outcome and Expected preserve trivial=
ity in copy, move, assignment and destruction. Both provide strong never em=
pty guarantees. Currently only Outcome preserves standard layout-ness, but =
Vicente is open to Expected also doing so if Albuquerque likes the idea.</d=
iv><div>=C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin: 0;ma=
rgin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=
=3D"ltr"><div>=C2=A0</div><div>(9) Niall wrote: "If you are adding a f=
eature which uses 98% of an existing feature, then the standard should requ=
ire use of that existing feature." =C2=A0I strongly disagree with that=
statement. Now, I *do* think (and I think Niall might agree) that we shoul=
d not add new features with small gratuitous quirks that make them impossib=
le to implement in terms of other standard features. To take two examples o=
f the "gratuitous quirk" problem: std::packaged_task<R(A...)&g=
t; is not implementable in terms of std::function<R(A...)> because co=
pyability, and std::vector<T,A>::resize is not implementable in terms=
of std::uninitialized_move_if_<wbr>noexcept() because allocator_traits. Th=
erefore, if it were truly *impossible* to implement Expected<T,E> in =
terms of std::variant<T,E>, I'd complain.</div><div>HOWEVER, I re=
peat that no sane implementation should pull in <variant> as a result=
of including <expected>. The former is a "higher-level" fe=
ature than the latter; it includes a ton of TMP machinery that is not neede=
d by <expected>. I might expect both headers to include some "he=
lper" header providing just the common parts needed by both.</div></di=
v></blockquote><div><br></div><div>This is <b>exactly</b>=C2=A0what I want =
to see: <basic_variant></div><div>=C2=A0</div><blockquote class=3D"gm=
ail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc soli=
d;padding-left: 1ex;"><div dir=3D"ltr"><div>We see an example of this in bo=
th libstdc++ and libc++, where <set> and <map> are implemented =
in terms of a "helper" header sometimes named <__tree>.=C2=
=A0 It is theoretically possible to implement std::map<K,V> in terms =
of std::set<something_clever<K,V><wbr>>, but no sane implementa=
tion will pull in all of <set> as a result of including <map>.<=
/div><div>I hope this clarifies my position.</div></div></blockquote><div><=
br></div><div>Dinkumware's STL is also full of common internal implemen=
tation classes shared by the public ones.</div><div><br></div><div>What bug=
s me severely is that frequently I am writing code which needs a=C2=A0<i>su=
bset</i>=C2=A0of a STL container, and lo and behold haven't all three m=
ajor STL implementations found the exact same problem and have internal cla=
sses implementing <i>exactly</i>=C2=A0what I need.</div><div><br></div><div=
>Those internal classes should be standardised into C++! Those internal cla=
sses are often a damn sight more useful than the official STL classes, but =
they're usually made private costing me and countless others effort in =
reinventing a wheel reinvented many times already.</div><div>=C2=A0</div><b=
lockquote class=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;borde=
r-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><br></div>=
<div>(10) Speaking of "levelization", I do like the idea of havin=
g "higher-level" and "lower-level" headers in the STL. =
I think it's unfortunate that <system_error> =E2=80=94 which soun=
ds like a low-level header =E2=80=94 actually depends on <string>, wh=
ich recursively depends on most of the STL (<string_view>, <ostrea=
m>, et cetera). I talked to Charley about this at CppCon: I'm ambiva=
lent. On the one hand I think it really sucks that <system_error> has=
any dependencies at all. On the other hand, I appreciate the idea of "=
;vocabulary types," and it feels hypocritical to condemn the library&#=
39;s own use of `std::string` as the vocabulary type for returning a string=
..</div></div></blockquote><div><br></div><div>The reason it depends on stri=
ng is that Beman felt that message strings would be generally programmatica=
lly, and therefore need memory allocation and freeing once done.</div><div>=
<br></div><div>And indeed on Windows they are generated programmatically, l=
ocalised to the current user language.</div><div>=C2=A0</div><blockquote cl=
ass=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px =
#ccc solid;padding-left: 1ex;"><div dir=3D"ltr"><div><br></div><div>(11) Ni=
all writes: "Outcome uses struct storage, not union storage."</di=
v><div>The paper Jens and I were reading flatly contradicts that statement,=
on page 4, where it says "Result requires the following layout to be =
implemented:" and then shows a piece of code involving a union. Howeve=
r, the reference C implementation</div><div>on page 14 uses a non-union str=
uct, and the reference C++ implementation on page 17 uses a "non-stand=
ard" optional<T> with the caveats listed in a comment at the bot=
tom of page 16.=C2=A0 It would be much *much* clearer if the new paper didn=
't imply the use of a union/optional/variant; it would save Niall a lot=
of argumentation. If you want a standard-layout struct, just use one! Don&=
#39;t even put "union" in your sample code!</div></div></blockquo=
te><div><br></div><div>Others also found draft 1 confusing. Outcome v2 has =
always used struct storage, it was a recommendation by the peer review. I&#=
39;ve uploaded an interim draft 2 paper on another thread to hopefully clar=
ify this problem.</div><div>=C2=A0</div><blockquote class=3D"gmail_quote" s=
tyle=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-le=
ft: 1ex;"><div dir=3D"ltr"><div><br></div><div>(12) Niall writes: "E i=
s not necessarily an error for Expected. It's merely an 'unexpected=
'." This is a distinction without a difference. Whether we call it=
an "error", an "unexpected result", or an "except=
ional state", the point is that it's a "disappointment" =
(to use Lawrence Crowl's term). The user's expectations are that fo=
o.value() will give them the normal-path result (if any), and that foo.erro=
r() will give them the "disappointment-path" result (if any). Jen=
s points out, rightly, that if the user asks for foo.error() and there is n=
o disappointment to report, it makes some sense to return "no error&qu=
ot; as opposed to blowing up the program via a thrown exception or via unde=
fined behavior. As to the question of whether we can generally consider a d=
efault-constructed E to indicate "no error", please see my point =
(1) in this email.</div></div></blockquote><div><br></div><div>I thought Je=
ns was making a stronger point than this actually. He seemed to feel that t=
hese objects aren't returning disappointment, they are returning an <i>=
error</i>. That's a much stronger meaning than <i>failure</i>, let alon=
e disappointment.</div><div><br></div><div>And I'm fairly much in agree=
ment on that. Draft 2 paper tries to get into the importance of starting yo=
ur design with a clearly defined mission and use case. Lots of "tricky=
" decisions fall into place if everyone is onboard regarding what prob=
lem we are solving.</div><div>=C2=A0</div><blockquote class=3D"gmail_quote"=
style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-=
left: 1ex;"><div dir=3D"ltr"><div><br></div><div>(13) I don't see the u=
sefulness of outcome<X,Y,Z>; but I know that if I don't like it I=
can avoid using it, and it sounds like Niall is not proposing that one for=
standardization anyway. (That is, he's proposing it for Boost.Outcome =
but not for C++2a.)</div></div></blockquote><div>=C2=A0</div><div>outcome&l=
t;T, EC, E|P> is definitely a Boost-ism. As are the policy classes, ADL =
injection points, and all that other stuff Boost folk love. I only mentione=
d it to demonstrate there are design layers of increasing complexity in Out=
come, that's all. A subset of those might be better to standardise than=
one single object design to rule them all.</div><div><br></div><div>Niall<=
/div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/7e4b7d7d-a3ae-42c0-930b-f53131f1d7c2%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/7e4b7d7d-a3ae-42c0-930b-f53131f1d7c2=
%40isocpp.org</a>.<br />
------=_Part_7379_2015959300.1507066403242--
------=_Part_7378_495309180.1507066403242--
.
Author: Niall Douglas <nialldouglas14@gmail.com>
Date: Tue, 3 Oct 2017 14:36:46 -0700 (PDT)
Raw View
------=_Part_7413_1728678213.1507066606669
Content-Type: multipart/alternative;
boundary="----=_Part_7414_939013486.1507066606669"
------=_Part_7414_939013486.1507066606669
Content-Type: text/plain; charset="UTF-8"
>
>
> In Niall's case, he's checking std::is_base_of, which will report true
> even for private inheritance <https://stackoverflow.com/a/2911185/1424877>,
> even though *I assume* the things he's going to try to do with the "E"
> type will eventually require public inheritance (e.g. convertibility).
>
I only use std::is_base_of because it's fast for the compiler to evaluate,
not because it's correct. If we had Concepts, you'd actually ask "does this
type quack like a std::error_code?"
I would recommend std-proposals consider my use of it as an irrelevant
implementation detail confined to a potential Boost.Outcome library only.
You'll notice interim draft 2 paper has completely dropped any mention of
std::is_base_of as it is distracting from the main message.
Niall
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/13b3bfac-66f0-4c1a-a32e-8745450b7ed4%40isocpp.org.
------=_Part_7414_939013486.1507066606669
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><blockquote class=3D"gmail_quote" style=3D"margin: 0;margi=
n-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;"><div dir=3D"l=
tr"><div class=3D"gmail_quote"><div><br></div><div>In Niall's case, he&=
#39;s checking std::is_base_of, which <a href=3D"https://stackoverflow.com/=
a/2911185/1424877" target=3D"_blank" rel=3D"nofollow" onmousedown=3D"this.h=
ref=3D'https://www.google.com/url?q\x3dhttps%3A%2F%2Fstackoverflow.com%=
2Fa%2F2911185%2F1424877\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFEW1RSFVn75=
qMvrMtqrUCUbqTe4Q';return true;" onclick=3D"this.href=3D'https://ww=
w.google.com/url?q\x3dhttps%3A%2F%2Fstackoverflow.com%2Fa%2F2911185%2F14248=
77\x26sa\x3dD\x26sntz\x3d1\x26usg\x3dAFQjCNFEW1RSFVn75qMvrMtqrUCUbqTe4Q'=
;;return true;">will report true even for private inheritance</a>, even tho=
ugh <i>I assume</i> the things he's going to try to do with the "E=
" type will eventually require public inheritance (e.g. convertibility=
).</div></div></div></blockquote><div>=C2=A0</div><div>I only use std::is_b=
ase_of because it's fast for the compiler to evaluate, not because it&#=
39;s correct. If we had Concepts, you'd actually ask "does this ty=
pe quack like a std::error_code?"</div><div><br></div><div>I would rec=
ommend std-proposals consider my use of it as an irrelevant implementation =
detail confined to a potential Boost.Outcome library only. You'll notic=
e interim draft 2 paper has completely dropped any mention of std::is_base_=
of as it is distracting from the main message.</div><div><br></div><div>Nia=
ll</div><div><br></div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/13b3bfac-66f0-4c1a-a32e-8745450b7ed4%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/13b3bfac-66f0-4c1a-a32e-8745450b7ed4=
%40isocpp.org</a>.<br />
------=_Part_7414_939013486.1507066606669--
------=_Part_7413_1728678213.1507066606669--
.
Author: Niall Douglas <nialldouglas14@gmail.com>
Date: Tue, 3 Oct 2017 14:52:14 -0700 (PDT)
Raw View
------=_Part_7337_674460903.1507067534960
Content-Type: multipart/alternative;
boundary="----=_Part_7338_737625298.1507067534960"
------=_Part_7338_737625298.1507067534960
Content-Type: text/plain; charset="UTF-8"
>
> There's a union where an "unsigned int" is shared with E; this should
> simply go. If you want to show standard-layout, just show
>
> struct result {
> T _value;
> /* integral or so */ discriminator;
> E _error;
> };
>
> However, prescribing this order of members might be sub-optimal in
> terms of alignment / packing of T and E; some other order might
> yield a smaller "result" layout on some platforms for some T and E.
>
This is the struct in interim draft 2 paper:
struct
{
T value;
// flags bit 0 set if value contains a T instance (and E is to be ignored)
// flags bit 1 set if value does not contain a T (and E is to be observed)
// flags bit 4 set if error is a generic POSIX errno int
(std::generic_category, std::errc enum)
unsigned int flags;
E error;
};
Assuming that 99% of the time that E will either be a std::error_code
(struct { int code; void *category; }) or some enum, the above layout on 32
bit should be optimal much of the time as the unsigned and int ought to
pack together.
On 64 bit, the error code will pad to 8 bytes, and there is wastage. But I
intentionally chose for 32 bit to pad well as I figured it more important
there.
Now I consider it, I can't actually drop the union around E error after
all, it loses the padding on 64 bit systems. I think I'll go use the actual
implementation in Outcome which is confusing, but correct.
I sympathize, but I still feel allowing something custom
> such as
>
> struct my_E {
> std::error_code ec;
> std::filesystem::path failed_path;
> std::string failed_function;
> };
>
> is the way to go here. If, on your way out, you need to strip
> that info down (maybe after logging) to E = std::error_code, you
> just pick the relevant member.
That would break TRY which needs type E to be consistent across all
functions.
Lest you think that TRY not be so important, I can assure you that it is an
*enormous* boilerplate saver in real world code using these objects.
Sufficiently a boon in fact that you'll deliberately choose in a code base
of any size or complexity a single type E for your entire program.
In Outcome v2, this is implemented via a macro OUTCOME_TRY or the superior
OUTCOME_TRYX if you are on GCC or clang. For WG21, I am submitting the
paper "D0779R0: Proposing operator try()" with Vicente.
> (I have a feeling that creating
> a std::exception_ptr is non-cheap, so requiring people to transport
> extra info via that mechanism seems not a good idea.)
>
Constructing one costs about 3000 to 5000 CPU cycles.
Niall
--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-proposals@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/32b0f9d0-5258-4794-b668-d3c17441ecc7%40isocpp.org.
------=_Part_7338_737625298.1507067534960
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><blockquote class=3D"gmail_quote" style=3D"margin: 0;margi=
n-left: 0.8ex;border-left: 1px #ccc solid;padding-left: 1ex;">There's a=
union where an "unsigned int" is shared with E; this should
<br>simply go. =C2=A0If you want to show standard-layout, just show
<br>
<br>=C2=A0 struct result {
<br>=C2=A0 =C2=A0 T _value;
<br>=C2=A0 =C2=A0 /* integral or so */ discriminator;
<br>=C2=A0 =C2=A0 E _error;
<br>=C2=A0 };
<br>
<br>However, prescribing this order of members might be sub-optimal in
<br>terms of alignment / packing of T and E; some other order might
<br>yield a smaller "result" layout on some platforms for some T =
and E.
<br></blockquote><div><br></div><div>This is the struct in interim draft 2 =
paper:</div><div><br></div><div><div>struct</div><div>{</div><div>=C2=A0 T =
value;</div><div>=C2=A0 // flags bit 0 set if value contains a T instance (=
and E is to be ignored)</div><div>=C2=A0 // flags bit 1 set if value does n=
ot contain a T (and E is to be observed)</div><div>=C2=A0 // flags bit 4 se=
t if error is a generic POSIX errno int (std::generic_category, std::errc e=
num)</div><div>=C2=A0 unsigned int flags;</div><div>=C2=A0 E error;</div><d=
iv>};</div></div><div><br></div><div>Assuming that 99% of the time that E w=
ill either be a std::error_code (struct { int code; void *category; }) or s=
ome enum, the above layout on 32 bit should be optimal much of the time as =
the unsigned and int ought to pack together.</div><div><br></div><div>On 64=
bit, the error code will pad to 8 bytes, and there is wastage. But I inten=
tionally chose for 32 bit to pad well as I figured it more important there.=
</div><div><br></div><div>Now I consider it, I can't actually drop the =
union around E error after all, it loses the padding on 64 bit systems. I t=
hink I'll go use the actual implementation in Outcome which is confusin=
g, but correct.</div><div><br></div><blockquote class=3D"gmail_quote" style=
=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #ccc solid;padding-left: =
1ex;">=C2=A0I sympathize, but I still feel allowing something custom
<br>such as
<br>
<br>=C2=A0 struct my_E {
<br>=C2=A0 =C2=A0std::error_code ec;
<br>=C2=A0 =C2=A0std::filesystem::path failed_path;
<br>=C2=A0 =C2=A0std::string failed_function;
<br>=C2=A0 };
<br>
<br>is the way to go here. =C2=A0If, on your way out, you need to strip
<br>that info down (maybe after logging) to E =3D std::error_code, you
<br>just pick the relevant member.</blockquote><div><br></div><div>That wou=
ld break TRY which needs type E to be consistent across all functions.</div=
><div><br></div><div>Lest you think that TRY not be so important, I can ass=
ure you that it is an <b>enormous</b>=C2=A0boilerplate saver in real world =
code using these objects. Sufficiently a boon in fact that you'll delib=
erately choose in a code base of any size or complexity a single type E for=
your entire program.</div><div><br></div><div>In Outcome v2, this is imple=
mented via a macro OUTCOME_TRY or the superior OUTCOME_TRYX if you are on G=
CC or clang. For WG21, I am submitting the paper "D0779R0: Proposing o=
perator try()" with Vicente.</div><div>=C2=A0</div><blockquote class=
=3D"gmail_quote" style=3D"margin: 0;margin-left: 0.8ex;border-left: 1px #cc=
c solid;padding-left: 1ex;"> =C2=A0(I have a feeling that creating
<br>a std::exception_ptr is non-cheap, so requiring people to transport
<br>extra info via that mechanism seems not a good idea.)
<br></blockquote><div><br></div><div>Constructing one costs about 3000 to 5=
000 CPU cycles.</div><div><br></div><div>Niall</div></div>
<p></p>
-- <br />
You received this message because you are subscribed to the Google Groups &=
quot;ISO C++ Standard - Future Proposals" group.<br />
To unsubscribe from this group and stop receiving emails from it, send an e=
mail to <a href=3D"mailto:std-proposals+unsubscribe@isocpp.org">std-proposa=
ls+unsubscribe@isocpp.org</a>.<br />
To post to this group, send email to <a href=3D"mailto:std-proposals@isocpp=
..org">std-proposals@isocpp.org</a>.<br />
To view this discussion on the web visit <a href=3D"https://groups.google.c=
om/a/isocpp.org/d/msgid/std-proposals/32b0f9d0-5258-4794-b668-d3c17441ecc7%=
40isocpp.org?utm_medium=3Demail&utm_source=3Dfooter">https://groups.google.=
com/a/isocpp.org/d/msgid/std-proposals/32b0f9d0-5258-4794-b668-d3c17441ecc7=
%40isocpp.org</a>.<br />
------=_Part_7338_737625298.1507067534960--
------=_Part_7337_674460903.1507067534960--
.