forked from ptal/std-expected-proposal
-
Notifications
You must be signed in to change notification settings - Fork 0
/
expected-proposal.tex
executable file
·2923 lines (2384 loc) · 120 KB
/
expected-proposal.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
\documentclass[a4paper,10pt]{article}
\usepackage[american]
{babel} % needed for iso dates
\usepackage{url}
\usepackage{lmodern}
\usepackage{listings}
\usepackage{graphicx}
\usepackage{xcolor}
\usepackage[T1]{fontenc}
\usepackage{textcomp}
\usepackage{hyperref}
\usepackage{array}
\usepackage{underscore}
\usepackage{changepage} % for the adjustwidth environment
\usepackage[top=2cm, bottom=2cm, left=2cm, right=2cm]{geometry}
\usepackage{color}
\usepackage{textpos}
\usepackage{titling}
\usepackage{titlesec}
\hypersetup{
hidelinks
}
\setcounter{secnumdepth}{6}
% From std draft
% We use the 'listings' package, with some small customizations. The
% most interesting customization: all TeX commands are available
% within comments. Comments are set in italics, keywords and strings
% don't get special treatment.
% General code style
\lstset{language=C++,
basicstyle=\small\ttfamily,
keywordstyle=,
stringstyle=,
xleftmargin=1em,
showstringspaces=false,
commentstyle=\itshape\rmfamily,
columns=flexible,
keepspaces=true,
texcl=true
}
% end from std draft
\newcommand{\wordingSec}[2]{\vspace{15pt}
\noindent
{\large\textbf{X.Y\quad #1\hfill\textbf{[#2]}}}
}
% Counters
\newcounter{countWordingSubSec}
\newcounter{countWordingSubSubSec}[countWordingSubSec]
\renewcommand{\thecountWordingSubSec}{X.Y.\arabic{countWordingSubSec}}
\renewcommand{\thecountWordingSubSubSec}{X.Y.\arabic{countWordingSubSec}.\arabic{countWordingSubSubSec}}
% Defs of sub and subsub section (for the wording).
\newcommand{\wordingSubSec}[2]{\vspace{15pt}
\refstepcounter{countWordingSubSec}
\noindent
{\textbf{\thecountWordingSubSec\quad #1\hfill\textbf{[#2]}}}
\label{#2}
\vspace{7pt}
}
\newcommand{\wordingSubSubSec}[2]{\vspace{15pt}
\refstepcounter{countWordingSubSubSec}
\noindent
{\textbf{\thecountWordingSubSubSec\quad #1\hfill\textbf{[#2]}}}
\label{#2}
\vspace{7pt}
}
\newcommand{\cpp}[1]{\lstinline{#1}}
\newcommand{\todo}[1]{\emph{\textcolor{red}{TODO: #1}}}
% Wording items
\newcommand{\wordingItem}[1]{\noindent\textit{#1:}}
\newenvironment{wordingTextItem}[1]{\wordingItem{#1}\vspace{2pt}\noindent\begin{adjustwidth}{12pt}{}}{\vspace{2pt}\end{adjustwidth}}
\newenvironment{wordingNoteItem}{[\wordingItem{Note}}{---\textit{end note}]}
\newenvironment{wordingPara}{\begin{adjustwidth}{12pt}{}}{\end{adjustwidth}}
\lstset{
xleftmargin=12pt
}
\setlength{\droptitle}{10em}
\title{A proposal to add a utility class to represent expected monad}
\author{}
\date{}
\begin{document}
\maketitle
\begin{textblock*}{9cm}(7cm,-8cm)
\begin{tabular}{l l}
\textbf{Document number:} & N4015 \\
\textbf{Date:} & 2014-05-26 \\
\textbf{Revises:} & None \\
\textbf{Project:} & JTC1.22.32 Programming \\
& Language C++ \\
\textbf{Reply to:} & Vicente J. Botet Escriba \\
& <\href{mailto:[email protected]}{[email protected]}> \\
& Pierre Talbot <\href{mailto:[email protected]}{[email protected]}>
\end{tabular}
\end{textblock*}
\vspace{-6em}
\setcounter{tocdepth}{1}
\tableofcontents
\section{Introduction}
%%%%%%%%%%%
Class template \cpp{expected<E,T>} proposed here is a type that may contain a value of type \cpp{T} or a value of type \cpp{E} in its storage space. \cpp{T} represents the expected value, \cpp{E} represents the reason explaining why it doesn't contains a value of type \cpp{T}, that is the unexpected value. Its interface allows to query if the underlying value is either the expected value (of type \cpp{T}) or an unexpected value (of type \cpp{E}). The original idea comes from Andrei Alexandrescu C++ and Beyond 2012: Systematic Error Handling in C++ talk \cite{AlexandrescuExpected}. The interface and the rational are based on \cpp{std::optional} N3793 \cite{OptionalRev5} and Haskell monads. We can consider that \cpp{expected<E,T>} is a generalization of \cpp{optional<T>} providing in addition a monad interface and some specific functions associated to the unexpected type \cpp{E}. It requires no changes to core language, and breaks no existing code.
\section{Motivation and Scope}
\label{motiv-scope}
%%%%%%%%%%%%%%%%
Basically, the two main error mechanisms are exceptions and return codes. Before further explanation, we should ask us what are the characteristics of a good error mechanism.
\begin{itemize}
\item \textbf{Error visibility} Failure cases should appears throughout the code review. Because the debug can be painful if the errors are hidden.
\item \textbf{Information on errors} The errors should carry out as most as possible information from their origin, causes and possibly the ways to resolve it.
\item \textbf{Clean code} The treatment of errors should be in a separate layer of code and as much invisible as possible. So the code reader could notice the presence of exceptional cases without stop his reading.
\item \textbf{Non-Intrusive error} The errors should not monopolize a communication channel dedicated to the normal code flow. They must be as discrete as possible. For instance, the return of a function is a channel that should not be exclusively reserved for errors.
\end{itemize}
The first and the third characteristic seem to be quite contradictory and deserve further explanation. The former points out that errors not handled should appear clearly in the code. The latter tells us that the error handling mustn't interfere with the code reading, meaning that it clearly shows the normal execution flow. A comparison between the exception and return codes is given in the table \ref{comp-handling-error}.
\begin{table}[h!]
\centering
\bgroup
\def\arraystretch{1.5}
\begin{tabular}{|l|>{\raggedright\arraybackslash}p{5cm}|>{\raggedright\arraybackslash}p{5cm}|}
\hline
& \textbf{Exception} & \textbf{Return code} \\
\hline
\textbf{Visibility} & Not visible without further analysis of the code. However, if an exception is thrown, we can follow the stack trace. & Visible at the first sight by watching the prototype of the called function. However ignoring return code can lead to undefined results and it can be hard to figure out the problem. \\
\hline
\textbf{Informations} & Exceptions can be arbitrarily rich. & Historically a simple integer. Nowadays, the header \cpp{<system_error>} provides richer error code. \\
\hline
\textbf{Clean code} & Provides clean code, exceptions can be completely invisible for the caller. & Force you to add, at least, a if statement after each function call. \\
\hline
\textbf{Non-Intrusive} & Proper communication channel. & Monopolization of the return channel. \\
\hline
\end{tabular}
\egroup
\caption{Comparison between two error handling systems.}
\label{comp-handling-error}
\end{table}
\subsection{Expected class}
%%%%%%%%%%%%%%%%%%%%
We can do the same analysis for the \cpp{Expected<E, T>} class and observe the advantages over the classic error reporting systems.
\begin{itemize}
\item \textbf{Error visibility} It takes the best of the exception and error code. It's visible because the return type is Expected<E, T> and the user cannot ignore the error case if he wants to retrieve the contained value.
\item \textbf{Information} Arbitrarily rich.
\item \textbf{Clean code} The monadic interface of expected provides a framework delegating the error handling to another layer of code. Note that \cpp{Expected<E, T>} can also act as a bridge between an exception-oriented code and a nothrow world.
\item \textbf{Non-Intrusive} Use the return channel without monopolizing it.
\end{itemize}
\noindent
It worths mentioning the other characteristics of \cpp{Expected<E, T>}:
\begin{itemize}
\item Associates errors with computational goals.
\item Naturally allows multiple errors inflight.
\item Teleportation possible.
\begin{itemize}
\item Across thread boundaries.
\item Across nothrow subsystem boundaries.
\item Across time: save now, throw later.
\end{itemize}
\item Collect, group, combine errors.
\end{itemize}
\section{Use cases}
%%%%%%%%%%
\subsection{Safe division}
\label{divide-example}
%%%%%%%%%%%
This example shows how to define a safe divide operation checking for divide-by-zero conditions. Using exceptions, we might write something like this:
\begin{lstlisting}
struct DivideByZero: public std::exception {...};
double safe_divide(double i, double j)
{
if (j==0) throw DivideByZero();
else return i / j;
}
\end{lstlisting}
With \cpp{Expected<E,T>}, we are not required to use exceptions, we can use \cpp{std::error_condition} which is easier to introspect than \cpp{std::exception_ptr} if we want to use the error. For the purpose of this example, we use the following enumeration (the boilerplate code concerning \cpp{std::error_condition} is not shown):
\begin{lstlisting}
enum class arithmetic_errc
{
divide_by_zero, // 9/0 == ?
not_integer_division // 5/2 == 2.5 (which is not an integer)
};
\end{lstlisting}
\noindent
Using \cpp{expected<error_condition, double>}, the code becomes:
\begin{lstlisting}
expected<error_condition, double> safe_divide(double i, double j)
{
if (j==0) return make_unexpected(arithmetic_errc::divide_by_zero); // (1)
else return i / j; // (2)
}
\end{lstlisting}
(1) The implicit conversion from \cpp{unexpected_type<E>} to \cpp{expected<E,T>} and (2) from \cpp{T} to \cpp{expected<E,T>} prevents using too much boilerplate code. The advantages are that we have a clean way to fail without using the exception machinery, and we can give precise information about why it failed as well. The liability is that this function is going to be tedious to use. For instance, the exception-based function $i + j/k$ is:
\begin{lstlisting}
double f1(double i, double j, double k)
{
return i + safe_divide(j,k);
}
\end{lstlisting}
\noindent
but becomes using \texttt{expected<error_condition, double>}:
\begin{lstlisting}
expected<error_condition, double> f1(double i, double j, double k)
{
auto q = safe_divide(j, k)
if(q) return i + *q;
else return q;
}
\end{lstlisting}
\noindent
This example clearly doesn't respect the ``clean code'' characteristic introduced in section \ref{motiv-scope} and the readability doesn't differ much from the ``C return code''. Hopefully, we can see \cpp{expected<E,T>} through functional glasses as a monad. The code is cleaner using the member function \cpp{map}. This way, the error handling is not explicitly mentioned but we still know, thanks to the call to \cpp{map}, that something is going underneath and thus it is not as silent as exception.
\begin{lstlisting}
expected<error_condition, double> f1(double i, double j, double k)
{
return safe_divide(j, k).map([&](double q){
return i + q;
});
}
\end{lstlisting}
The \cpp{map} member calls the continuation provided if expected contains a value, otherwise it forwards the error to the callee. Using lambda function might clutter the code, so here the same example using functor:
\begin{lstlisting}
expected<error_condition, double> f1(double i, double j, double k)
{
return safe_divide(j, k).map(bind(plus, i, _1));
}
\end{lstlisting}
We can use \cpp{expected<E, T>} to represent different error conditions. For instance, with integer division, we might want to fail if the two numbers are not evenly divisible as well as checking for division by zero. We can overload our \cpp{safe_divide} function accordingly:
\begin{lstlisting}
expected<error_condition, int> safe_divide(int i, int j)
{
if (j == 0) return make_unexpected(arithmetic_errc::divide_by_zero);
if (i%j != 0) return make_unexpected(arithmetic_errc::not_integer_division);
else return i / j;
}
\end{lstlisting}
Now we have a division function for integers that possibly fail in two ways. We continue with the exception-oriented function $i/k + j/k$:
\begin{lstlisting}
int f2(int i, int j, int k)
{
return safe_divide(i,k) + safe_divide(j,k);
}
\end{lstlisting}
\noindent
Now let's write this code using an \cpp{expected<E,T>} type and the functional \cpp{map} already used previously.
\begin{lstlisting}
expected<error_condition, int> f(int i, int j, int k)
{
return safe_divide(i, k).map([=](int q1) {
return safe_divide(j,k).map([=](int q2) {
return q1+q2;
});
});
}
\end{lstlisting}
The compiler will gently say he can convert an \cpp{expected<error_condition, expected<error_condition, int>>} to \cpp{expected<error_condition, int>}. This is because the member \cpp{map} wraps the result in Expected and since we use twice the \cpp{map} member it wraps it twice. The \cpp{bind}\footnote{To not confound with \cpp{std::bind} which is not related to monad.} member wraps the result of the continuation only if it is not already wrapped. The correct version is as follow:
\begin{lstlisting}
expected<error_condition, int> f(int i, int j, int k)
{
return safe_divide(i, k).bind([=](int q1) {
return safe_divide(j,k).bind([=](int q2) {
return q1+q2;
});
});
}
\end{lstlisting}
The error-handling code has completely disappeared but the lambda functions are a new source of noise, and this is even more important with $n$ expected variables. Propositions for a better monadic experience are discussed in section \ref{better-support-for-monad}, the subject is left open and is considered out of scope of this proposal.
\subsection{Error retrieval and correction}
%%%%%%%%%%%%%%%%
The major advantage of \cpp{expected<E,T>} over \cpp{optional<T>} is the ability to transport an error, but we didn't come yet to an example that retrieve the error. First of all, we should wonder what a programmer do when a function call returns an error:
\begin{enumerate}
\item Ignore it.
\item Delegate the responsibility of error handling to higher layer.
\item Trying to resolve the error.
\end{enumerate}
Because the first behavior might lead to buggy application, we won't consider it in a first time. The handling is dependent of the underlying error type, we consider the \cpp{exception_ptr} and the \cpp{error_condition} types.
We spoke about how to use the value contained in the Expected but didn't discuss yet the error usage. A first imperative way to use our error is to simply extract it from the Expected using the \cpp{error()} member function. The following example shows a \cpp{divide2} function that return 0 if the error is \cpp{divide_by_zero}:
\begin{lstlisting}
expected<error_condition, int> divide2(int i, int j)
{
auto e = safe_divide(i,j);
if (!e && e.error().value() == arithmetic_errc::divide_by_zero) {
return 0;
}
return e;
}
\end{lstlisting}
This imperative way is not entirely satisfactory since it suffers from the same disadvantages than \cpp{value()}. Again, a functional view leads to a better solution. The \cpp{catch_error} member calls the continuation passed as argument if the expected is erroneous.
\begin{lstlisting}
expected<error_condition, int> divide3(int i, int j)
{
auto e = safe_divide(i,j);
return e.catch_error([](const error_condition& e){
if(e.value() == arithmetic_errc::divide_by_zero)
{
return 0;
}
return make_unexpected(e);
});
}
\end{lstlisting}
An advantage of this version is to be coherent with the \cpp{bind} and \cpp{map} functions. It also provides a more uniform way to analyze error and recover from some of these. Finally, it encourages the user to code its own ``error-resolver'' function and leads to a code with distinct treatment layers.
\section{Impacts on the Standard}
%%%%%%%%%%%%%%%%%
These changes are entirely based on library extensions and do not require any language features beyond what is available in C++ 14. It requires however the \cpp{in_place_t} from N3793.
\section{Design rationale}
%%%%%%%%%%%%%
The same rationale described in \cite{OptionalRev4} for \cpp{optional<T>} applies to \cpp{expected<E,T>} and \cpp{expected<nullopt_t, T>} should behave as \cpp{optional<T>}. That is, we see \cpp{expected<E,T>} as \cpp{optional<T>} for which all the values of \cpp{E} collapse into a single value \cpp{nullopt}. In the following sections we present the specificities of the rationale in \cite{OptionalRev4} applied to \cpp{expected<E,T>}.
\subsection{Conceptual model of \cpp{expected<E,T>}}
%%%%%%%%%%%%%%%%%%%%%%%%%%%
\cpp{expected<E,T>} models a discriminated union of types \cpp{T} and \cpp{unexpected_type<E>}. \cpp{expected<E,T>} is viewed as a value of type \cpp{T} or value of type \cpp{unexpected_type<E>}, allocated in the same storage, along with the way of determining which of the two it is.
The interface in this model requires operations such as comparison to \cpp{T}, comparison to \cpp{E}, assignment and creation from either. It is easy to determine what the value of the expected object is in this model: the type it stores (\cpp{T} or \cpp{E}) and either the value of \cpp{T} or the value of \cpp{E}.
Additionally, within the affordable limits, we propose the view that \cpp{expected<E,T>} extends the set of the values of \cpp{T} by the values of type \cpp{E}. This is reflected in initialization, assignment, ordering, and equality comparison with both \cpp{T} and \cpp{E}. In the case of \cpp{optional<T>}, \cpp{T} can not be a \cpp{nullopt_t}. As the types \cpp{T} and \cpp{E} could be the same in \cpp{expected<E,T>}, there is need to tag the values of \cpp{E} to avoid ambiguous expressions. The \cpp{make_unexpected(E)} function is proposed for this purpose. However \cpp{T} can not be \cpp{unexpected_type<E>} for a given \cpp{E}.
\begin{lstlisting}
expected<string, int> ei = 0;
expected<string, int> ej = 1;
expected<string, int> ek = make_unexpected(string());
ei = 1;
ej = make_unexpected(E());;
ek = 0;
ei = make_unexpected(E());;
ej = 0;
ek = 1;
\end{lstlisting}
\subsection{Initialization of \cpp{expected<E,T>}}
%%%%%%%%%%%%%%%%%%%%%%%
an
In cases \cpp{T} and \cpp{E} are value semantic types capable of storing \cpp{n} and \cpp{m} distinct values respectively, \cpp{expected<E,T>} can be seen as an extended \cpp{T} capable of storing \cpp{n + m} values: these that \cpp{T} and \cpp{E} stores. Any valid initialization scheme must provide a way to put an expected object to any of these states. In addition, some \cpp{T}'s are not \cpp{CopyConstructible} and their expected variants still should be constructible with any set of arguments that work for \cpp{T}.
\noindent
As in \cite{OptionalRev4}, the model retained is to initialize either by providing an already constructed \cpp{T} or a tagged \cpp{E}. The default constructor required \cpp{E} to be default-constructible (which is more likely to happen than \cpp{T}).
\begin{lstlisting}
string s{"STR"};
expected<error_condition,string> es{s}; // requires Copyable<T>
expected<error_condition,string> et = s; // requires Copyable<T>
expected<error_condition,string> ev = string{"STR"}; // requires Movable<T>
expected<error_condition,string> ew; // unexpected value
expected<error_condition,string> ex{}; // unexpected value
expected<error_condition,string> ey = {}; // unexpected value
expected<error_condition,string> ez = expected<error_condition,string>{}; // unexpected value
\end{lstlisting}
\noindent
In order to create an unexpected object, the special function \cpp{make_unexpected} needs to be used:
\begin{lstlisting}
expected<int, string> ep{make_unexpected(-1)}; // unexpected value, requires Movable<E>
expected<int, string> eq = make_unexpected(-1); // unexpected value, requires Movable<E>
\end{lstlisting}
\noindent
As in \cite{OptionalRev4}, and in order to avoid calling move/copy constructor of \cpp{T}, we use a ``tagged'' placement constructor:
\begin{lstlisting}
expected<error_condition,MoveOnly> eg; // unexpected value
expected<error_condition,MoveOnly> eh{}; // unexpected value
expected<error_condition,MoveOnly> ei{in_place}; // calls MoveOnly{} in place
expected<error_condition,MoveOnly> ej{in_place, "arg"}; // calls MoveOnly{"arg"} in place
\end{lstlisting}
\noindent
To avoid calling move/copy constructor of \cpp{E}, we use a ``tagged'' placement constructor:
\begin{lstlisting}
expected<string,int> ei{unexpect}; // unexpected value, calls string{} in place
expected<string,int> ej{unexpect, "arg"}; // unexpected value, calls string{"arg"} in place
\end{lstlisting}
\noindent
An alternative name for \cpp{in_place} that is coherent with \cpp{unexpect} could be \cpp{expect}. Being compatible with \cpp{optional<T>} seems more important. So this proposal doesn't propose such a \cpp{expect} tag.
\newline
The alternative and also comprehensive initialization approach, which is not compatible with the default construction of \cpp{expected<E,T>} to \cpp{E()}, could have been a variadic perfect forwarding constructor that just forwards any set of arguments to the constructor of the contained object of type \cpp{T}.
\subsection{Almost never-empty guaranty}
%%%%%%%%%%%%%%%%%%
As \cpp{boost::variant<unexpected_type<E>,T>}, \cpp{expected<E,T>} ensures that it is never empty. All instances \cpp{v} of type \cpp{expected<E,T>} guarantee that \cpp{v} has constructed content of one of the types \cpp{T} or \cpp{E}, even if an operation on \cpp{v} has previously failed.
This implies that expected may be viewed precisely as a union of exactly its bounded types. This ``never-empty'' property insulates the user from the possibility of undefined expected content and the significant additional complexity-of-use attendant with such a possibility.
\subsubsection{The default constructor}
%%%%%%%%%%%%%%%%%%
Similar data structure includes \cpp{optional<T>}, \lstinline[mathescape]{variant<$T_1$,...,$T_n$>} and \cpp{future<T>}. We can compare how they are default constructed.
\begin{itemize}
\item \cpp{std::experimental::optional<T>} default constructs to an optional with no value.
\item \lstinline[mathescape]{boost::variant<$T_1$,...,$T_n$>} default constructs to the first type default constructible or it is ill-formed if none are default constructible.
\item \cpp{std::future<T>} default constructs to an invalid future with no shared state associated, that is, no value and no exception.
\item \cpp{std::experimental::optional<T>} default constructor is equivalent to \cpp{boost::variant<nullopt_t, T>}.
\end{itemize}
\noindent
It raises several questions about \cpp{expected<E,T>}:
\begin{itemize}
\item Should the default constructor of \cpp{expected<E,T>} behave like \cpp{variant<T,E>} or as \cpp{variant<E,T>}?
\item Should the default constructor of \cpp{expected<E,T>} behave like \cpp{optional<variant<T,E>>}?
\item Should the default constructor of \cpp{expected<nullopt_t,T>} behave like \cpp{optional<T>}? If yes, how should behave the default constructor of \cpp{expected<E,T>}? As if initialized with \cpp{make_unexpected(E())}? This would be equivalent to the initialization of \cpp{variant<E,T>}.
\item Should \cpp{expected<E,T>} provide a default constructor at all? \cite{OptionalRev3} presents valid arguments against this approach, e.g. \cpp{array<expected<E,T>>} would not be possible.
\end{itemize}
Requiring \cpp{E} to be default constructible seems less constraining than requiring \cpp{T} to be default constructible (e.g. consider the \cpp{Date} example in \cite{OptionalRev3}). With the same semantics \cpp{expected<E,Date>} would be \cpp{Regular} with a meaningful not-a-date state created by default.
There is still a minor issue as the default constructor of \cpp{std::exception_ptr} doesn't contains an exception and so getting the value of a default constructed \cpp{expected<exception_ptr, T>} would need to check if the stored \cpp{std::exception_ptr} is equal to \cpp{std::exception_ptr()} and throw a specific exception.
The authors consider the arguments in \cite{OptionalRev3} valid and so propose that \cpp{expected<E,T>} default constructor should behave as constructed with \cpp{make_unexpected(E())}.
\subsubsection{Conversion from \cpp{T}}
%%%%%%%%%%%%%%%%%%
An object of type \cpp{T} is convertible to an expected object of type \cpp{expected<E,T>}:
\begin{lstlisting}
expected<error_condition, int> ei = 1; // works
\end{lstlisting}
\noindent
This convenience feature is not strictly necessary because you can achieve the same effect by using tagged forwarding constructor:
\begin{lstlisting}
expected<error_condition, int> ei{in_place, 1};
\end{lstlisting}
\noindent
If the latter appears too cumbersome, one can always use function \cpp{make_expected} described below:
\begin{lstlisting}
expected<error_condition, int> ei = make_expected(1);
auto ej = make_expected(1);
\end{lstlisting}
\subsubsection{Conversion from \cpp{E}}
%%%%%%%%%%%%%%%%%%
An object of type \cpp{E} is not convertible to an unexpected object of type \cpp{expected<E,T>} since \cpp{E} and \cpp{T} can be of the same type. The proposed interface uses a special tag \cpp{unexpect} and a special non-member \cpp{make_unexpected} function to indicate an unexpected state for \cpp{expected<E,T>}. It is used for construction and assignment. This might rise a couple of objections. First, this duplication is not strictly necessary because you can achieve the same effect by using the \cpp{unexpect} tagged forwarding constructor:
\begin{lstlisting}
expected<int, string> exp1 = make_unexpected(1);
expected<int, string> exp2 = {unexpect, 1};
exp1 = make_unexpected(1);
exp2 = {unexpect, 1};
\end{lstlisting}
\noindent
While some situations would work with the \cpp{\{unexpect, ...\}} syntax, using \cpp{make_unexpected} makes the programmer's intention as clear and less cryptic. Compare these:
\begin{lstlisting}
expected<int, vector<int>> get1() {
return {unexpect, 1};
}
expected<int, vector<int>> get2() {
return make_unexpected(1);
}
expected<int, vector<int>> get3() {
return expected<int, vector<int>>{unexpect, 1};
}
\end{lstlisting}
The usage of \cpp{make_unexpected} is also a consequence of the adapted model for expected: a discriminated union of \cpp{T} and \cpp{unexpected_type<E>}. While \cpp{make_unexpected(E)} has been chosen because it clearly indicates that we are interested in creating an unexpected \cpp{expected<E,T>} (of unspecified type \cpp{T}), it could be also used to make a ready future with a specific error, but this is outside the scope of this proposal. Note also that the definition of the result type of \cpp{make_unexpected} has an explicitly deleted default constructor. This is in order to enable the reset idiom \cpp{exp2 = \{\}} which would otherwise not work due to the ambiguity when deducing the right-hand side argument.
\subsection{Observers}
%%%%%%%%%%%%%%%%%%
In order to be as efficient as possible, this proposal includes observers with narrow and wide contracts. Thus, the \cpp{value()} function has a wide contract. If the expected object doesn't contain a value, an exception is thrown. However, when the user knows that the expected object is valid, the use of \cpp{operator*} would be more appropriated.
\subsubsection{Explicit conversion to \cpp{bool}}
%%%%%%%%%%%%%%%%%%
The rational described in \cite{OptionalRev4} for \cpp{optional<T>} applies to \cpp{expected<E,T>} and so, the following example combines initialization and value-checking in a boolean context.
\begin{lstlisting}
if (expected<error_condition, char> ch = readNextChar()) {
// ...
}
\end{lstlisting}
\subsubsection{Accessing the contained value}
%%%%%%%%%%%%%%%%%%
Even if \cpp{expected<E,T>} has not been used in practice for a while as Boost.Optional, we consider that following the same interface that \cpp{std::experimental::optional<T>} makes the C++ standard library more homogeneous. The rational described in \cite{OptionalRev4} for \cpp{optional<T>} applies to \cpp{expected<E,T>}.
\subsubsection{Dereference operator}
%%%%%%%%%%%%%%%%%%
It was chosen to use indirection operator because, along with explicit conversion to \cpp{bool}, it is a very common pattern for accessing a value that might not be there:
\begin{lstlisting}
if (p) use(*p);
\end{lstlisting}
This pattern is used for all sort of pointers (smart or raw) and \cpp{optional}; it clearly indicates the fact that the value may be missing and that we return a reference rather than a value. The indirection operator has risen some objections because it may incorrectly imply that \cpp{expected} and \cpp{optional} are a (possibly smart) pointer, and thus provides shallow copy and comparison semantics. All library components so far use indirection operator to return an object that is not part of the pointer's/iterator's value. In contrast, \cpp{expected} as well as \cpp{optional} indirects to the part of its own state. We do not consider it a problem in the design; it is more like an unprecedented usage of indirection operator. We believe that the cost of potential confusion is overweighted by the benefit of an intuitive interface for accessing the contained value.
We do not think that providing an implicit conversion to \cpp{T} would be a good choice. First, it would require different way of checking for the empty state; and second, such implicit conversion is not perfect and still requires other means of accessing the contained value if we want to call a member function on it.
Using the indirection operator for a object that doesn't contain a value is an undefined behavior. This behavior offers maximum runtime performance.
\subsubsection{Function value}
%%%%%%%%%%%%%%%%%%
In addition to the indirection operator, we propose the member function value as in \cite{OptionalRev4} that returns a reference to the contained value if one exists or throw an exception otherwise.
\begin{lstlisting}
void interact() {
string s;
cout << "enter number: ";
cin >> s;
expected<error,int> ei = str2int(s);
try {
process_int(ei.value());
}
catch(bad_expected_access<error>) {
cout << "this was not a number.";
}
}
\end{lstlisting}
The exception thrown depend on the expected error type. By default it throws \cpp{bad_expected_access<E>} (derived from \cpp{logic_error}) which will contain the stored error. In the case of \cpp{expected<exception_ptr>}, it throws the exception stored in the \cpp{exception_ptr}. An approach enabling customization of this behavior is presented in the section \ref{configurable-expected}.
\cpp{bad_expected_access<E>} and \cpp{bad_optional_access} could inherit both from a \cpp{bad_access} exception derived from \cpp{logic_error}, but this is not proposed.
\subsubsection{Accessing the contained error}
%%%%%%%%%%%%%%%%%%%%%%%
Usually, accessing the contained error is done once we know the expected object has no value. This is why the \cpp{error()} function has a narrow contract: it works only if \cpp{!(*this)}.
\begin{lstlisting}
expected<errc,int> getIntOrZero(istream_range& r){
auto r = getInt(); // won't throw
if (!r && r.error() == errc::empty_stream){
return 0;
}
return r;
}
\end{lstlisting}
\noindent
This behavior could not be obtained with the \cpp{value_or()} method since we want to return 0 only if the error is equal to \cpp{empty_stream}.
\subsubsection{Conversion to the unexpected value}
%%%%%%%%%%%%%%%%%%
As the \cpp{error()} function, the \cpp{get_unexpected()} works only if the expected object has no value. It is used to propagate errors. Note that the following equivalences yield:
\begin{lstlisting}
f.get_unexpected() == make_unexpected(f.error());
f.get_unexpected() == expected<E, T>{unexpect, f.error()};
\end{lstlisting}
\noindent
This member is provided for convenience, it is further demonstrated in the next example:
\begin{lstlisting}
expected<errc, pair<int, int>> getIntRange(istream_range& r) {
auto f = getInt(r);
if (!f) return f.get_unexpected();
auto m = matchedString("..", r);
if (!m) return m.get_unexpected();
auto l = getInt(r);
if (!l) return l.get_unexpected();
return std::make_pair(*f, *l);
}
\end{lstlisting}
\cpp{get_unexpected} is also provided for symmetry purpose. On one side, there is an implicit conversion from \cpp{unexpected<E>} to \cpp{expected<E,T>} and on the other side there is an explicit conversion from \cpp{expected<E,T>} to \cpp{unexpected<E>}. A more pleasant function manipulating error is \cpp{catch_error(F)} and is explained in the monadic operations in section \ref{monadic-operations}.
\subsubsection{Function \cpp{value_or}}
%%%%%%%%%%%%%%%%%%
The function member \cpp{value_or()} has the same semantics than \cpp{optional}\cite{OptionalRev4} since the type of \cpp{E} doesn't matter; hence we can consider that \cpp{E == nullopt_t} and the optional semantics yields. Using the monadic interface, we can achieve a similar behavior:
\begin{lstlisting}
auto x = getInt();
int x = *(x.catch_error([](auto){return 0;})); // identical to x.value_or(0);
\end{lstlisting}
\subsubsection{Relational operators}
%%%%%%%%%%%%%%%%%%
The relational operators have the same semantics than \cpp{optional}\cite{OptionalRev5}. Of course, the error type can be anything but it'll never participate in ordering, thus we can consider than \cpp{E == nullopt_t}; hence the semantics of optional can be exactly mapped. We considered that we can compare \cpp{unexpected_type} but it seems that errors are not structure that have a semantic ordering. Therefore it is coherent to use the same semantics than \cpp{optional}.
\subsection{Modifiers}
%%%%%%%%%%%%%%%%%%
\subsubsection{Reseting the value}
%%%%%%%%%%%%%%%%%%
Reseting the value of \cpp{expected<E,T>} is similar to \cpp{optional<T>} but instead of building a disengaged \cpp{optional<T>}, we build a erroneous \cpp{expected<E,T>}. Hence, the semantics and rational is the same than in \cite{OptionalRev4}.
\subsubsection{Tag \cpp{in_place}}
%%%%%%%%%%%%%%%%%%
This proposal makes use of the "in-place" tag defined in \cite{OptionalRev5}. This proposal provides the same kind of "in-place" constructor that forwards (perfectly) the arguments provided to \cpp{expected}'s constructor into the constructor of \cpp{T}. In order to trigger this constructor one has to use the tag struct \cpp{in_place}. We need the extra tag to disambiguate certain situations, like calling \cpp{expected}'s default constructor and requesting \cpp{T}'s default construction:
\begin{lstlisting}
expected<error, Big> eb{in_place, "1"}; // calls Big{"1"} in place (no moving)
expected<error, Big> ec{in_place}; // calls Big{} in place (no moving)
expected<error, Big> ed{}; // calls error{} (unexpected state)
\end{lstlisting}
\subsubsection{Tag \cpp{unexpect}}
%%%%%%%%%%%%%%%%%%
This proposal provides an "unexpect" constructor that forwards (perfectly) the arguments provided to \cpp{expected}'s constructor into the constructor of \cpp{E}. In order to trigger this constructor one has to use the tag struct \cpp{unexpect}. We need the extra tag to disambiguate certain situations, notably if \cpp{T == E}.
\begin{lstlisting}
expected<error, Big> eb{unexpect, "1"}; // calls error{"1"} in place (no moving)
expected<error, Big> ec{unexpect}; // calls error{} in place (no moving)
\end{lstlisting}
In order to make the tag uniform an additional "expect" constructor could be provided but this proposal doesn't propose it.
\subsubsection{Requirements on \cpp{T} and \cpp{E}}
%%%%%%%%%%%%%%%%%%
Class template \cpp{expected} imposes little requirements on \cpp{T} and \cpp{E}: they have to be complete object type satisfying the requirements of \cpp{Destructible}. Each operations on \cpp{expected<E,T>} have different requirements and may be disable if \cpp{T} or \cpp{E} doesn't respect these requirements. For example, \cpp{expected<E,T>}'s move constructor requires that \cpp{T} and \cpp{E} are \cpp{MoveConstructible}, \cpp{expected<E,T>}'s copy constructor requires that \cpp{T} and \cpp{E} are \cpp{CopyConstructible}, and so on. This is because \cpp{expected<E,T>} is a wrapper for \cpp{T} or \cpp{E}: it should resemble \cpp{T} as much as possible. If \cpp{T} is \cpp{EqualityComparable} then (and only then) we expect \cpp{expected<E,T>} to be \cpp{EqualityComparable}.
\subsubsection{Expected references}
%%%%%%%%%%%%%%%%%%
This proposal doesn't include expected references as \cpp{optional}\cite{OptionalRev5} doesn't include references neither.
\subsubsection{Expected void}
%%%%%%%%%%%%%%%%%%
While it could seem weird to instantiate optional with \cpp{void}, it has more sense for expected as it conveys in addition, as \cpp{future<T>}, an error state.
\subsection{Making \cpp{expected} a literal type}
%%%%%%%%%%%%%%%%%%
In \cite{OptionalRev4}, they propose to make \cpp{optional} a literal type, the same reasoning can be applied to \cpp{expected}. Under some conditions, such that \cpp{T} and \cpp{E} are trivially destructible, and the same described for \cpp{optional}, we propose that \cpp{expected} be a literal type.
\subsection{Moved from state}
%%%%%%%%%%%%%%%%%%
We follow the approach taken in \cpp{optional}\cite{OptionalRev4}. Moving \cpp{expected<E,T>} do not modify the state of the source (valued or erroneous) of \cpp{expected} and the move semantics is up to \cpp{T} or \cpp{E}.
\subsection{IO operations}
%%%%%%%%%%%%%%%%%%
For the same reasons than \cpp{optional}\cite{OptionalRev4} we do not add \cpp{operator<<} and \cpp{operator>>} IO operations.
\subsection{Monadic operations}
\label{monadic-operations}
%%%%%%%%%%
A monadic interface is not optional if we don't want to fall back in the problems of the old "C return code". The example section \ref{divide-example} shows how these operations are important to expected. The member function \cpp{map} and \cpp{bind} find their roots in the category theory if we consider \cpp{expected} as a functor and a monad.
\subsubsection{Functor \cpp{map}}
The operation \cpp{map} consider expected as a functor and just apply a function on the contained value, if any. The types of the two overloads are presented using a functional notation and the \cpp{[]} represent a context in which the value T or U is contained. The current context is \cpp{expected} and thus \cpp{[T]} is equivalent to \cpp{expected<E,T>}.
\begin{itemize}
\item \cpp{(T -> U) -> [U]}
\item \cpp{(T -> [U]) -> [[U]]}
\end{itemize}
Whatever the return type of the continuation, we observe that it is always wrapped into a context. The monadic bind do it differently.
\subsubsection{Monadic \cpp{bind}}
A monad is defined with a type constructor and two operations \cpp{return} and \cpp{bind}. The type constructor simply build a monad for a specific type, in the C++ jargon it is referred to template instantiation (we build \cpp{expected} from a type \cpp{Value} and \cpp{Error}).
The \cpp{return} operation wraps a value of type \cpp{T} inside a context \cpp{[T]}. In C++ we can consider the constructors as a \cpp{return} operation.
Finally, the \cpp{bind} operation is similar to \cpp{map} but doesn't wrap the value if the function already wraps it up. The functional signature of \cpp{bind} can be described as follow:
\begin{itemize}
\item \cpp{(T -> U) -> [U]}
\item \cpp{(T -> [U]) -> [U]}
\end{itemize}
If a do-notation is introduced in C++, as proposed in section \ref{better-support-for-monad}, these operations can become a powerful abstraction, they have been proven very useful in Haskell. For example, a similar interface could be used with \cpp{optional}..
\subsubsection{\cpp{then} operation}
The last operation has no direct counterpart in functional language and is inspired from \cite{ImprovementsAsync} proposing some improvements to \cpp{std::future<T>}. The functional signature is as follow:
\begin{itemize}
\item \cpp{([T] -> U) -> [U]}
\item \cpp{([T] -> [U]) -> [U]}
\end{itemize}
It has the same wrapping strategy than \cpp{bind}: it doesn't wrap if the continuation already wraps it up.
\subsubsection{Exception thrown in the continuation}
This behavior is left open in the section \ref{configurable-expected}. Currently, the exceptions thrown in the continuations are not caught.
\subsubsection{\cpp{catch_error} operation}
This last member function is used when we want to use or recover from an error. When chaining multiple \cpp{bind} or \cpp{map} operations we don't know if the operations have succeeded. A common way is thus to add a \cpp{catch_error} at the end and act in consequence.
\begin{lstlisting}
getInt().map([](int i){return i * 2;})
.map(integer_divide_by_2)
.catch_error(log_error);
\end{lstlisting}
\noindent
Here the last operation is simply used to log the error but the \cpp{catch_error} also accepts function that try to recover from a previous error.
\begin{lstlisting}
getInt().map([](int i){return i * 2;})
.map(integer_divide_by_2)
.catch_error([](auto e) { return 0; });
\end{lstlisting}
\noindent
This last example shows we can return a new value from the continuation passed to \cpp{catch_error}.
\newline
The \cpp{catch_error} member doesn't catch exceptions that could be thrown by the continuation. Since we already try to recover from an error it makes little sense to prevent the user to launch an exception.
\subsubsection{Function \cpp{unwrap}}
%%%%%%%%%%
In some scenarios, you might want to create an \cpp{expected} that returns another \cpp{expected}, resulting in nested expected. It is possible to write simple code to unwrap the outer \cpp{expected} and retrieve the nested \cpp{expected} and its result with the current interface as in:
\begin{lstlisting}
template <class T, class E>
expected<E,T> unwrap<expected<E, expected<E,T>> ee) {
if (ee) return *ee;
return ee.get_unexpected();
}
template <class T, class E>
expected<E,T> unwrap<expected<E,T>> e) {
return e;
}
\end{lstlisting}
We could add such a function to the standard, either as a free function or as a member function. The authors propose to add it as a member function to be in line with \cite{ImprovementsAsync}.
\section{Related types}
%%%%%%%%%%%
\subsection{Variant}
%%%%%%%%%%%%%%%%%%%%
\cpp{expected<E,T>} can be seen as a specialization of \cpp{boost::variant<unexpected<E>,T>} which gives a specific intent to its second parameter, that is, it represents the type of the expected contained value. This specificity allows to provide a pointer like interface, as it is the case for \cpp{std::experimental::optional<T>}. Even if the standard included a class \cpp{variant<T,E>}, the interface provided by \cpp{expected<E,T>} is more specific and closer to what the user could expect as the result type of a function. In addition, \cpp{expected<E,T>} doesn't intend to be used to define recursive data as \cpp{boost::variant<>} does.
The table \ref{comp-variant} presents a brief comparison between \cpp{boost::variant<unexpected<E>, T>} and \cpp{expected<E,T>}.
\begin{table}[h!]
\bgroup
\def\arraystretch{1.5}
\begin{tabular}
{|l|>{\raggedright\arraybackslash}p{6cm}|>{\raggedright\arraybackslash}p{6cm}|}
\hline
& \textbf{boost::variant<unexpected<E>, T>} & \textbf{expected<E,T>} \\
\hline
\textbf{never-empty warranty} & yes & yes \\
\hline
\textbf{accepts is_same<T,E>} & no & yes \\
\hline
\textbf{swap} & yes & yes \\
\hline
\textbf{factories} & no & make\_expected / make\_unexpected \\
\hline
\textbf{hash} & yes & yes \\
\hline
\textbf{value_type} & no & yes \\
\hline
\textbf{default constructor} & yes (if T is default constructible) & yes (if T is default constructible) \\
\hline
\textbf{observers} & boost::get<T> and boost::get<E> & pointer-like / value / error / value_or \\
\hline
\textbf{continuations} & apply_visitor & map/bind/then/catch_error \\
\hline
\end{tabular}
\egroup
\caption{Comparison between variant and expected.}
\label{comp-variant}
\end{table}
\subsection{Optional}
%%%%%%%%%%%
We can see \cpp{expected<E,T>} as an \cpp{std::experimental::optional<T>} that collapse all the values of \cpp{E} to \cpp{nullopt}. We can convert an \cpp{expected<E,T>} to an \cpp{optional<T>} with the possible loss of information.
\begin{lstlisting}
template <class T>
optional<T> make_optional(expected<E,T> v) {
if (v) return make_optional(*v);
else nullopt;
}
\end{lstlisting}
\noindent
We can convert an \cpp{optional<T>} to an \cpp{expected<E,T>} without knowledge of the root cause. We consider that \cpp{E()} is equal to \cpp{nullopt} since it shouldn't bring more informations (however it depends on the underlying error --- we considered \cpp{exception_ptr} and \cpp{error_condition}).
\begin{lstlisting}
template <class T, class E>
expected<E,T> make_expected(optional<T> v) {
if (v) return make_expected(*v);
else make_unexpected(E());
}
\end{lstlisting}
\subsection{Promise and Future}
%%%%%%%%%%%%%%%%%
We can see \cpp{expected<exception_ptr,T>} as an always ready \cpp{future<T>}. While \cpp{promise<>}/\cpp{future<>} focuses on inter-thread asynchronous communication, \cpp{excepted<E,T>} focus on eager and synchronous computations.
We can move a ready \cpp{future<T>} to an \cpp{expected<exception_ptr,T>} with no loss of information.
\begin{lstlisting}
template <class T>
expected<exception_ptr,T> make_expected(future<T>&& f) {
assert (f.ready() && "future not ready");
try {
return f.get();
} catch (...) {
return make_unexpected_from_exception();
}
}
\end{lstlisting}
\noindent
We can also create a \cpp{future<T>} from an \cpp{expected<exception_ptr,T>}.
\begin{lstlisting}
template <class T>
future<T> make_ready_future(expected<exception_ptr,T> e) {
if (e)
return make_ready_future(*e);
else
return make_unexpected_future<T>(e.error());
}
\end{lstlisting}
\noindent
where \cpp{make_unexpected_future} is defined as:
\begin{lstlisting}
template <class T, class E>
constexpr future<T> make_unexpected_future(E e) {
promise<T> p;
future<T> f = p.get_future();
p.set_exception(e);
return move(f);
}
\end{lstlisting}
\noindent
We can combine them as follows:
\begin{lstlisting}
fut.then([](future<int> f) {
return make_ready_future(
make_expected(f).bind([](i){ ... }).catch_error(...));
});
\end{lstlisting}
As for the \cpp{future<T>} proposal, \cpp{expected<E,T>} provides also a way to visit the stored values.
\cpp{future<T>} provides a \cpp{then()} function that accepts a continuation having the \cpp{future<T>} as parameter. The synchronous nature of expected makes it easier to use two functions, one to manage with the case expected has a value and one to try to recover otherwise. This is more in line with the monad interface, as any function having a \cpp{T} as parameter can be used as parameter of the apply function, no need to have a \cpp{expected<E,T>}. This make it easier to reuse functions.
\begin{itemize}
\item \cpp{expected<E,T>::then()} is the counterpart of \cpp{future<T>.then()}
\item \cpp{expected<E,T>::unwrap()} is the counterpart of \cpp{future<T>.unwrap()}
\item \cpp{expected<E,T>::operator bool()} is the counterpart of \cpp{future<T>.has_value()}
\end{itemize}
\subsection{Comparison between optional, expected and future}
The table \ref{comp-monads} presents a brief comparison between \cpp{optional<T>}, \cpp{expected<E,T>} and \cpp{promise<T>/future<T>}.
\begin{table}
\bgroup
\def\arraystretch{1.5}
\begin{tabular}{|l|>{\raggedright\arraybackslash}p{4cm}|>{\raggedright\arraybackslash}p{4cm}|>{\raggedright\arraybackslash}p{4cm}|}
\hline
& \textbf{optional} & \textbf{expected} & \textbf{promise/future} \\
\hline
\textbf{specific null value} & yes & no & no \\
\hline
\textbf{relational operators} & yes & yes & no \\
\hline
\textbf{swap} & yes & yes & yes \\
\hline
\textbf{factories} & make_optional / nullopt & make_expected / make_unexpected & make_ready_future / (make_exceptional, see \cite{MoreAsync}) \\
\hline
\textbf{hash} & yes & yes & yes \\
\hline
\textbf{value_type} & yes & yes & no / (yes, see \cite{MoreAsync}). \\
\hline
\textbf{default constructor} & yes & yes (if T is default constructible) & yes \\
\hline
\textbf{allocators} & no & no & yes \\
\hline
\textbf{emplace} & yes & yes & no \\
\hline
\textbf{bool conversion} & yes & yes & no \\
\hline
\textbf{state} & bool() & bool() / valid & valid / ready / (has_value, see \cite{MoreAsync}) \\
\hline
\textbf{observers} & pointer-like / value / value_or & pointer-like / value / error / value_or & get / (get_exception_ptr, see \cite{MoreAsync}) \\
\hline
\textbf{visitation} & no & map / bind / then / catch_error & then / (next/recover see \cite{MoreAsync}) \\
\hline
\textbf{grouping} & n/a & n/a & when_all / when_any \\
\hline
\end{tabular}
\egroup
\caption{Comparison between optional, expected and promise/future.}
\label{comp-monads}
\end{table}
\section{Open points}
%%%%%%%%%%%%%
\subsection{Better support for monad}
\label{better-support-for-monad}
In the use-cases section (\ref{divide-example}), we present expected as a better way to handle errors than exception or error code. However the current syntax using lambda and chaining monadic operations (such as \cpp{map}) can be tedious to use. We propose different solutions to overcome this problem, since the solutions are more general than the scope of this proposal we discuss them in the open points section.
A first solution that do not require change in the language is the use of variadic monadic operation. For example using a variadic free function \cpp{map}, we can write the $i/k + j/k$ function as following:
\begin{lstlisting}
expected<exception_ptr,int> f(int i, int j, int k)
{
return map(plus,
safe_divide(i, k),
safe_divide(j, k));
}