Library: capture and transport the exception itself

...using the std::exception_ptr and helpers, we can now reliably
transport any exception object as the »right« value of the »Either«
This commit is contained in:
Fischlurch 2023-09-27 02:51:00 +02:00
parent 4348e110cb
commit 9c0fa7139d
4 changed files with 210 additions and 44 deletions

View file

@ -22,9 +22,9 @@
/** @file result.hpp
** Intermediary value object to represent the result of an operation.
** This operation might have produced a value result or failed with an exception.
** Typically, the Result token is used _inline_ -- immediately either invoking
** Intermediary value object to represent »either« an operation result or a failure.
** Some operation might have produced a value result or failed with an exception.
** Typically, the Result token is used _inline_ — immediately either invoking
** one of the member function or employing the built-in result type conversion.
** It will be copyable iff the result value is copyable. There is an implicit
** valid or failure state, which can be tested. Any attempt to get the value
@ -42,15 +42,14 @@
#include "lib/wrapper.hpp"
#include "lib/util.hpp"
#include <exception>
#include <utility>
#include <string>
namespace lib {
using util::isnil;
using std::string;
namespace error = lumiera::error;
@ -74,27 +73,27 @@ namespace lib {
template<>
class Result<void>
{
string failureLog_;
std::exception_ptr failure_;
public:
/** mark either failure (default) or success */
Result (bool success =false)
: failureLog_{success? "": "operation failed"}
: failure_{success? nullptr: std::make_exception_ptr (error::State{"operation failed"})}
{ }
/** failed result, with reason given.*/
Result (lumiera::Error const& reason)
: failureLog_{reason.what()}
: failure_{std::make_exception_ptr (reason)}
{ }
operator bool() const { return isValid(); }
bool isValid() const { return isnil (failureLog_); }
bool isValid() const { return not failure_; }
void
maybeThrow() const
{
if (not isValid())
throw error::State (failureLog_);
if (failure_)
std::rethrow_exception(failure_);
}
};
@ -115,12 +114,7 @@ namespace lib {
wrapper::ItemWrapper<RES> value_;
public:
/** mark an invalid/failed result */
Result (string const& failureReason ="no result")
: Result<void>{failureReason}
{ }
/** failed result, with reason given.*/
/** mark failed result, with reason given.*/
Result (lumiera::Error const& reason)
: Result<void>{reason}
{ }
@ -131,6 +125,7 @@ namespace lib {
, value_{std::forward<RES> (value)}
{ }
// is or is not copyable depending on RES
operator RES() const
@ -158,9 +153,9 @@ namespace lib {
}
};
/** deduction guard: allow _perfect forwarding_ of a any result into the ctor call. */
template<typename VAL>
Result (VAL&& x) -> Result<VAL>;
Result (VAL&&) -> Result<VAL>;

View file

@ -133,7 +133,7 @@ namespace model {
struct ElementAccess::TypeConverter
: RawResult::Visitor
{
lib::Result<TAR&> result{"not convertible to desired target widget"};
lib::Result<TAR&> result{error::Invalid{"not convertible to desired target widget"}};
template<typename X> // note the "backward" use. We pick that base interface
using canUpcast = std::is_convertible<TAR*, X>; // into which our desired result type can be upcast, because
@ -150,7 +150,7 @@ namespace model {
result = *downcasted;
}
else
result = lib::Result<TAR&>{"access returns empty answer"};
result = lib::Result<TAR&>{error::State{"access returns empty answer"}};
}
};

View file

@ -44,7 +44,6 @@ namespace test{
namespace error = lumiera::error;
using error::LUMIERA_ERROR_FATAL;
using error::LUMIERA_ERROR_STATE; ///////////////////TODO
namespace {
@ -89,12 +88,12 @@ namespace test{
CHECK (not isSameObject (sequel.get<Literal const&>(), THE_END));
// »Either Right« case : mark as failure
Result<double> facepalm{error::Fatal()};
Result<double> facepalm{error::Fatal("zOMG")};
CHECK (not facepalm.isValid());
VERIFY_ERROR (STATE, (double)facepalm );
VERIFY_ERROR (STATE, facepalm.get<double&>());
VERIFY_ERROR (STATE, facepalm.maybeThrow() );
VERIFY_ERROR (FATAL, (double)facepalm );
VERIFY_ERROR (FATAL, facepalm.get<double&>());
VERIFY_ERROR (FATAL, facepalm.maybeThrow() );
CHECK (42.0 == facepalm.getOrElse([]{ return 42; }));
}

View file

@ -79584,14 +79584,14 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695749704247" ID="ID_827179831" MODIFIED="1695749714510" TEXT="R&#xfc;ckgabewert per lib::Result">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1695749704247" ID="ID_827179831" MODIFIED="1695776492378" TEXT="R&#xfc;ckgabewert per lib::Result">
<icon BUILTIN="pencil"/>
<node CREATED="1695749715525" ID="ID_914625209" MODIFIED="1695749847745" TEXT="das ist ein Either-Typ">
<icon BUILTIN="yes"/>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695749719789" ID="ID_1636786367" MODIFIED="1695749844541" TEXT="diesen modernisieren">
<icon BUILTIN="flag-yellow"/>
<node CREATED="1695749730882" ID="ID_720335444" MODIFIED="1695749749631" TEXT="sollte einen std::exception_ptr nehmen">
<node COLOR="#338800" CREATED="1695749719789" ID="ID_1636786367" MODIFIED="1695776447431" TEXT="diesen modernisieren">
<icon BUILTIN="button_ok"/>
<node COLOR="#435e98" CREATED="1695749730882" ID="ID_720335444" MODIFIED="1695776449174" TEXT="sollte einen std::exception_ptr nehmen">
<icon BUILTIN="idea"/>
<node CREATED="1695749758416" ID="ID_1018098640" MODIFIED="1695749764076" TEXT="dieser dient als Varianten-Flag"/>
<node CREATED="1695749764647" ID="ID_160637410" MODIFIED="1695749781209">
@ -79620,6 +79620,26 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</body>
</html></richcontent>
</node>
<node COLOR="#435e98" CREATED="1695779117581" ID="ID_313781081" MODIFIED="1695779285785">
<richcontent TYPE="NODE"><html>
<head>
</head>
<body>
<p>
incl <i>perfect forwarding</i>
</p>
</body>
</html></richcontent>
<arrowlink COLOR="#7c86a6" DESTINATION="ID_1103669600" ENDARROW="Default" ENDINCLINATION="-1340;79;" ID="Arrow_ID_171962477" STARTARROW="None" STARTINCLINATION="-729;83;"/>
<icon BUILTIN="idea"/>
</node>
<node COLOR="#338800" CREATED="1695779300895" ID="ID_877020791" MODIFIED="1695779311935" TEXT="Result_test">
<icon BUILTIN="button_ok"/>
</node>
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1695776467076" ID="ID_992547663" MODIFIED="1695776489819" TEXT="den &#xbb;Either&#xab; value (lib::Result) per policy einbringen">
<icon BUILTIN="flag-yellow"/>
</node>
</node>
</node>
@ -79634,7 +79654,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
<node CREATED="1695657111918" ID="ID_463997820" MODIFIED="1695657217094" TEXT="in Sub-Namespace lib::thread">
<arrowlink COLOR="#6e85a1" DESTINATION="ID_750029588" ENDARROW="Default" ENDINCLINATION="-741;56;" ID="Arrow_ID_1885189676" STARTARROW="None" STARTINCLINATION="-489;0;"/>
</node>
<node CREATED="1695747369039" ID="ID_1807166092" MODIFIED="1695747532236" TEXT="immer noch unklar und problematisch">
<node CREATED="1695747369039" ID="ID_1807166092" MODIFIED="1695770884835" TEXT="immer noch unklar und problematisch">
<richcontent TYPE="NOTE"><html>
<head>
@ -79660,8 +79680,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
hab das gestern versucht &#8212; so kann das nicht stehen bleiben, das ist ja l&#228;cherlich (brauche explizite Template-Instantiierung) &#8212; zumindest solange wir keine C++-Module verwenden (C++20)
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
<node CREATED="1695747673046" ID="ID_1466067755" MODIFIED="1695747692667">
<richcontent TYPE="NODE"><html>
@ -79673,8 +79692,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
die Code-Anordnung&#160;<i>hat keinen Flow</i>
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<font NAME="SansSerif" SIZE="12"/>
</node>
<node CREATED="1695747880669" ID="ID_1803056303" MODIFIED="1695748482205" TEXT="die erzwungene &#xbb;Joinable&#xab;-Variante wirkt mutwillig">
@ -79687,8 +79705,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
Ich habe doch selber oben diese Prinzipien formuliert: eine Library-L&#246;sung sollte nicht mutwillig beschr&#228;nken, sondern eine sinnvolle Gliederung anbieten...
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<arrowlink COLOR="#fed5c5" DESTINATION="ID_1859841213" ENDARROW="Default" ENDINCLINATION="1276;51;" ID="Arrow_ID_1453893581" STARTARROW="None" STARTINCLINATION="1738;-79;"/>
<arrowlink COLOR="#8c5869" DESTINATION="ID_1245905649" ENDARROW="Default" ENDINCLINATION="10;123;" ID="Arrow_ID_155554446" STARTARROW="None" STARTINCLINATION="129;7;"/>
</node>
@ -79703,8 +79720,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
also vielleicht doch <b>Policy-based-Design</b>?
</p>
</body>
</html>
</richcontent>
</html></richcontent>
<icon BUILTIN="help"/>
<node CREATED="1695748635886" ID="ID_859201330" MODIFIED="1695748676734" TEXT="aaber ... dann wird ja alles noch umst&#xe4;ndlicher">
<icon BUILTIN="clanbomber"/>
@ -79722,8 +79738,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
&#10233; wenn &#252;berhaupt, m&#252;&#223;te die Policy einen <i>mittleren Binding-Layer </i>bilden
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
<node BACKGROUND_COLOR="#ccb59b" COLOR="#6e2a38" CREATED="1695749319298" ID="ID_1308996711" MODIFIED="1695749370296" TEXT="eine Policy f&#xfc;r Fehlerbehandlung + R&#xfc;ckgabewert + Join w&#xe4;re gerechtfertigt">
<linktarget COLOR="#dd26d2" DESTINATION="ID_1308996711" ENDARROW="Default" ENDINCLINATION="194;-5;" ID="Arrow_ID_1982134212" SOURCE="ID_1477111545" STARTARROW="None" STARTINCLINATION="172;16;"/>
@ -79748,8 +79763,7 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
Policy <font size="5"><b>&#10549;</b></font>&#160;<font color="#07097c" face="Monospaced">main&lt;POL,FUN,ARGS...&gt;</font>
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
</node>
<node CREATED="1695749669204" ID="ID_1950929730" MODIFIED="1695749680246" TEXT="Front-End: wie bisher"/>
@ -89176,6 +89190,164 @@ Date:&#160;&#160;&#160;Thu Apr 20 18:53:17 2023 +0200<br/>
</node>
</node>
</node>
<node CREATED="1695776592132" ID="ID_1103669600" LINK="https://en.cppreference.com/w/cpp/language/class_template_argument_deduction#Deduction_for_class_templates" MODIFIED="1695779285785" TEXT="via Class Template Argument Deduction (CTAD)">
<linktarget COLOR="#7c86a6" DESTINATION="ID_1103669600" ENDARROW="Default" ENDINCLINATION="-1340;79;" ID="Arrow_ID_171962477" SOURCE="ID_313781081" STARTARROW="None" STARTINCLINATION="-729;83;"/>
<node CREATED="1695776635546" ID="ID_536392621" MODIFIED="1695776837788" TEXT="geht normalerweise nicht &#x2014; da keine &#xbb;universelle Referenz&#xab;">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Wenn man eine Klasse C&lt;T&gt; hat, und einen Konstruktur definiert, der ein T&amp;&amp; - Argument nimmt, dann ist das T bereits durch den Klassen-Templateparameter <i>festgelegt; </i>es kommt in diesem Fall nicht zu einem <i>reference collapsing, </i>sondern es handelt sich einfach um eine rvalue-Referenz T&amp;&amp;. Symptom &quot;can not bind rvalue reference to lvalue&quot;
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1695776839723" ID="ID_304077427" MODIFIED="1695776912034" TEXT="Ein Konstruktor mit separatem Template-Parameter kann nicht deduziert werden">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...denn in diesem Fall w&#252;rde es sich zwar um eine &#187;universelle Referenz&#171; handeln, aber der Zusammenhang zum Klassen-Template-Parameter ist nicht klar
</p>
</body>
</html>
</richcontent>
</node>
<node CREATED="1695776913649" ID="ID_247930242" MODIFIED="1695777249133" TEXT="Abhilfe: expliziten deduction guide schreiben">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<ul>
<li>
steht im enclosing scope <i>nach</i>&#160;der Template-Definition
</li>
<li>
syntaktisch eine frei stehende Funktions-Deklaration mit einem <i>trailing return type</i>, welcher die resultierende Template-Spezialisierung konstruieren mu&#223; (kann beliebig komplexe Typ-Ausdr&#252;cke enthalten)
</li>
</ul>
<p>
</p>
<p>
<u>Beispiel </u>
</p>
<p>
<font face="Monospaced">&#160;&#160;/** deduction guard: allow _perfect forwarding_ of a any result into the ctor call. */ </font>
</p>
<p>
<font face="Monospaced">&#160;&#160;template&lt;typename VAL&gt; </font>
</p>
<p>
<font face="Monospaced">&#160;&#160;Result (VAL&amp;&amp;) -&gt; Result&lt;VAL&gt;; </font>
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="idea"/>
<node BACKGROUND_COLOR="#f0d5c5" COLOR="#990033" CREATED="1695777446740" ID="ID_1737574962" MODIFIED="1695778365679" TEXT="mit ist nicht klar, warum das dann funktioniert gem&#xe4;&#xdf; Standard">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
Wenn ich die Beschreibung in CPPReference.com richtig verstehe, dann w&#252;rde ohne expliziten deduction guide folgender guide automatisch generiert:
</p>
<p>
</p>
<p>
template&lt;class X&gt;
</p>
<p>
class C {
</p>
<p>
&#160;&#160;C(X&amp;&amp; val);
</p>
<p>
};
</p>
<p>
</p>
<p>
<u>Auto-Guides</u>:
</p>
<p>
</p>
<p>
template&lt;class X&gt;
</p>
<p>
C&lt;X&gt; g1(X&amp;&amp; val)
</p>
<p>
</p>
<p>
template&lt;class X&gt;
</p>
<p>
C&lt;X&gt; g2(C&lt;X&gt;)
</p>
<p>
</p>
<p>
<u>Hilfs-Deduction+Resolution...</u>
</p>
<p>
</p>
<p>
struct S {
</p>
<p>
&#160;&#160;template&lt;class X&gt;
</p>
<p>
&#160;&#160;S(X&amp;&amp;);
</p>
<p>
&#160;&#160;template&lt;class X&gt;
</p>
<p>
&#160;&#160;S(C&lt;X&gt;);
</p>
<p>
};
</p>
<p>
</p>
<p>
S = &lt;initializer&gt;
</p>
<p>
</p>
<p>
</p>
<p>
<font color="#8b2626"><b>Was ich nicht verstehe</b></font>: der gem&#228;&#223; Regeln auto-generierte Guide sieht <i>exakt genauso aus, </i>wie der Guide, den man manuell definieren mu&#223;, damit es funktioniert. Warum wird dann hier ein anderer Typ deduziert? Ich habe Experimente gemacht: ohne den manuellen deduction Guide ergibt sich f&#252;r einen &lt;initializer&gt; &#8788; int&amp;&#160;&#160;&#10236; ein deduzierter Parameter X = int&#160;&#160;(was dann nat&#252;rlich scheitert)
</p>
</body>
</html>
</richcontent>
<icon BUILTIN="help"/>
</node>
</node>
</node>
</node>
<node CREATED="1622386272743" ID="ID_1645901699" MODIFIED="1622386277362" TEXT="I/O">
<node CREATED="1622386278646" ID="ID_359102162" MODIFIED="1622386285472" TEXT="sehr gro&#xdf;e Dateien">