This repository has been archived by the owner on Jul 28, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
operator-question-mark.bs
101 lines (74 loc) · 4.19 KB
/
operator-question-mark.bs
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
<pre class=metadata>
Title: Error propagation via postfix operator <code>?</code>
Shortname: P0TBD
Revision: 0
Audience: LWG
Status: D
URL: https://serenityos.github.io/cpp-papers/operator-question-mark/
Group: WG21
!Source: <a href="https://github.com/SerenityOS/cpp-papers/blob/master/src/operator-question-mark.bs">https://github.com/SerenityOS/cpp-papers/blob/master/src/operator-question-mark.bs</a>
Editor: Brian Gianforcaro, bgianf@serenityos.org
Abstract: The postfix operator <code>?</code> short circuits execution flow by returning the error value contained by optional error types like <code>std::expected<T,E></code>.
Abstract: If the type contains no error value, then control continues as normal, and the value contained by the <code>std::expected<T,E></code> is the result of the expression.
Date: 2021-08-25
Markup Shorthands: markdown yes
</pre>
# Introduction # {#introduction}
The postfix operator `?` is designed to operate on utility classes like `std::optional<T>`[[N3793]] or `std::expected<T,E>` [[P0323r10]].
These types are designed to express that the result of some computation could produce a value `T` or an error `E`,
or in the case of `std::optional<T>` the absence of a value.
When utilizing these types in real world programs, a significant amount of program logic ends up revolving around
handling failure paths and properly propagating errors to the calling function.
To mitigate the need for this boilerplate the postfix operator `?` can be used to automatically obtain values from
success cases, or return the error value if present instead.
Similar functionality has been used with success in other languages, such as:
- [Trait based exception handling](https://github.com/rust-lang/rfcs/blob/master/text/0243-trait-based-exception-handling.md) used in Rust.
- [try expressions](https://ziglang.org/documentation/master/#try) used in Zig.
# Motivation # {#motivation}
## Use Cases ## {#use-cases}
### Networking Stack Error Handling ### {#networking-stack-error-handling-use-case}
The following is an example of how the SerenityOS Kernel networking stack [creates a socket pair](https://github.com/SerenityOS/serenity/blob/a28cd921a1df15a51555284cb74efc7d8758812f/Kernel/Net/LocalSocket.cpp), where `KResultOr<T>` is a type much like `std::expected<T,E>`
where its contract is to return a kernel error enum value, or a value of the template parameter `T`.
```cpp
KResultOr<SocketPair> LocalSocket::try_create_connected_pair(int type)
{
auto socket_or_error = LocalSocket::try_create(type);
if (socket_or_error.is_error())
return socket_or_error.error();
auto socket = socket_or_error.release_value();
auto description1_result = FileDescription::try_create(*socket);
if (description1_result.is_error())
return description1_result.error();
if (auto result = socket->try_set_path("[socketpair]"sv); result.is_error())
return result;
socket->set_acceptor(Process::current());
socket->set_connected(true);
socket->set_connect_side_role(Role::Connected);
socket->set_role(Role::Accepted);
auto description2_result = FileDescription::try_create(*socket);
if (description2_result.is_error())
return description2_result.error();
return SocketPair { description1_result.release_value(), description2_result.release_value() };
}
```
If we rewrite this code to instead use the proposed postfix operator `?` syntax, we get:
```cpp
KResultOr<SocketPair> LocalSocket::try_create_connected_pair(int type)
{
auto socket = LocalSocket::try_create(type)?;
auto description1 = FileDescription::try_create(*socket)?;
socket->try_set_path("[socketpair]"sv)?;
socket->set_acceptor(Process::current());
socket->set_connected(true);
socket->set_connect_side_role(Role::Connected);
socket->set_role(Role::Accepted);
auto description2 = FileDescription::try_create(*socket)?;
return SocketPair { move(description1), move(description2) };
}
```
# Proposal # {#proposal}
**TODO:** Incorporate some of the very nice background research from [[P0709r0]] here?
# Design rationale # {#design-rational}
# Proposed wording # {#proposed-wording}
# Implementability # {#implementability}
# Acknowledgements # {#acknowledgements}