├── .gitignore ├── .pre-commit-config.yaml ├── .github └── workflows │ ├── ci.yml │ └── deploy.yml ├── README.md └── src └── operator-question-mark.bs /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.html 3 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: local 3 | hooks: 4 | - id: bikeshed-build 5 | name: check bikeshed files build 6 | entry: bikeshed update && bikeshed spec 7 | language: python 8 | types: [file] 9 | files: \.bs$ 10 | additional_dependencies: ['bikeshed'] 11 | 12 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | pull_request: 4 | paths: ["src/**"] 5 | jobs: 6 | main: 7 | name: Build and Validate 8 | runs-on: ubuntu-20.04 9 | steps: 10 | - uses: actions/checkout@v2 11 | - uses: w3c/spec-prod@v2 12 | with: 13 | TOOLCHAIN: bikeshed 14 | SOURCE: src/operator-question-mark.bs 15 | VALIDATE_LINKS: true 16 | VALIDATE_MARKUP: true 17 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Auto Deployment 2 | on: 3 | push: 4 | branches: [master] 5 | paths: ["src/**"] 6 | 7 | jobs: 8 | main: 9 | name: Build, Validate and Deploy 10 | runs-on: ubuntu-20.04 11 | steps: 12 | - uses: actions/checkout@v2 13 | - uses: w3c/spec-prod@v2 14 | with: 15 | TOOLCHAIN: bikeshed 16 | SOURCE: src/operator-question-mark.bs 17 | DESTINATION: operator-question-mark/index.html 18 | VALIDATE_LINKS: true 19 | VALIDATE_MARKUP: true 20 | GH_PAGES_BRANCH: gh-pages 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | This repository tracks papers and proposals for the C++ standards committee. 4 | 5 | Papers are currently written in the [bikeshed] format, and are stored under the 6 | `src/` directory. The proposals are built, validated, and deployed to github pages 7 | on every push to master. 8 | 9 | # Current Proposals 10 | 11 | | Number | File | Title | Standard | Status | 12 | |:------:|:--------------------------------------------------------------:|:------------------------------------------------------------:|:-----------:|:---------:| 13 | | TBD | [src/operator-question-mark.bs](src/operator-question-mark.bs) | [Error Propagation Via Operator '?'][operator-question-mark] | Post C++23? | WIP Draft | 14 | 15 | 16 | # Links 17 | 18 | - [How To Submit a Proposal](https://isocpp.org/std/submit-a-proposal) 19 | 20 | [bikeshed]: https://github.com/tabatkins/bikeshed 21 | [operator-question-mark]: https://serenityos.github.io/cpp-papers/operator-question-mark/ 22 | 23 | -------------------------------------------------------------------------------- /src/operator-question-mark.bs: -------------------------------------------------------------------------------- 1 |
  2 | Title: Error propagation via postfix operator ?
  3 | Shortname: P0TBD
  4 | Revision: 0
  5 | Audience: LWG
  6 | Status: D
  7 | URL: https://serenityos.github.io/cpp-papers/operator-question-mark/
  8 | Group: WG21
  9 | !Source: https://github.com/SerenityOS/cpp-papers/blob/master/src/operator-question-mark.bs
 10 | Editor: Brian Gianforcaro, bgianf@serenityos.org
 11 | Abstract: The postfix operator ? short circuits execution flow by returning the error value contained by optional error types like std::expected<T,E>.
 12 | Abstract: If the type contains no error value, then control continues as normal, and the value contained by the std::expected<T,E> is the result of the expression.
 13 | Date: 2021-08-25
 14 | Markup Shorthands: markdown yes
 15 | 
16 | 17 | # Introduction # {#introduction} 18 | 19 | The postfix operator `?` is designed to operate on utility classes like `std::optional`[[N3793]] or `std::expected` [[P0323r10]]. 20 | These types are designed to express that the result of some computation could produce a value `T` or an error `E`, 21 | or in the case of `std::optional` the absence of a value. 22 | 23 | When utilizing these types in real world programs, a significant amount of program logic ends up revolving around 24 | handling failure paths and properly propagating errors to the calling function. 25 | 26 | To mitigate the need for this boilerplate the postfix operator `?` can be used to automatically obtain values from 27 | success cases, or return the error value if present instead. 28 | 29 | Similar functionality has been used with success in other languages, such as: 30 | - [Trait based exception handling](https://github.com/rust-lang/rfcs/blob/master/text/0243-trait-based-exception-handling.md) used in Rust. 31 | - [try expressions](https://ziglang.org/documentation/master/#try) used in Zig. 32 | 33 | # Motivation # {#motivation} 34 | 35 | ## Use Cases ## {#use-cases} 36 | 37 | ### Networking Stack Error Handling ### {#networking-stack-error-handling-use-case} 38 | 39 | 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` is a type much like `std::expected` 40 | where its contract is to return a kernel error enum value, or a value of the template parameter `T`. 41 | 42 | ```cpp 43 | KResultOr LocalSocket::try_create_connected_pair(int type) 44 | { 45 | auto socket_or_error = LocalSocket::try_create(type); 46 | if (socket_or_error.is_error()) 47 | return socket_or_error.error(); 48 | 49 | auto socket = socket_or_error.release_value(); 50 | 51 | auto description1_result = FileDescription::try_create(*socket); 52 | if (description1_result.is_error()) 53 | return description1_result.error(); 54 | 55 | if (auto result = socket->try_set_path("[socketpair]"sv); result.is_error()) 56 | return result; 57 | 58 | socket->set_acceptor(Process::current()); 59 | socket->set_connected(true); 60 | socket->set_connect_side_role(Role::Connected); 61 | socket->set_role(Role::Accepted); 62 | 63 | auto description2_result = FileDescription::try_create(*socket); 64 | if (description2_result.is_error()) 65 | return description2_result.error(); 66 | 67 | return SocketPair { description1_result.release_value(), description2_result.release_value() }; 68 | } 69 | ``` 70 | 71 | If we rewrite this code to instead use the proposed postfix operator `?` syntax, we get: 72 | ```cpp 73 | KResultOr LocalSocket::try_create_connected_pair(int type) 74 | { 75 | auto socket = LocalSocket::try_create(type)?; 76 | 77 | auto description1 = FileDescription::try_create(*socket)?; 78 | 79 | socket->try_set_path("[socketpair]"sv)?; 80 | socket->set_acceptor(Process::current()); 81 | socket->set_connected(true); 82 | socket->set_connect_side_role(Role::Connected); 83 | socket->set_role(Role::Accepted); 84 | 85 | auto description2 = FileDescription::try_create(*socket)?; 86 | 87 | return SocketPair { move(description1), move(description2) }; 88 | } 89 | ``` 90 | 91 | # Proposal # {#proposal} 92 | 93 | **TODO:** Incorporate some of the very nice background research from [[P0709r0]] here? 94 | 95 | # Design rationale # {#design-rational} 96 | 97 | # Proposed wording # {#proposed-wording} 98 | 99 | # Implementability # {#implementability} 100 | 101 | # Acknowledgements # {#acknowledgements} 102 | --------------------------------------------------------------------------------