|
| 1 | +# Error Handling |
| 2 | + |
| 3 | +Status: **Accepted** |
| 4 | + |
| 5 | +<details> |
| 6 | + <summary>Metadata</summary> |
| 7 | + <dl> |
| 8 | + <dt>Contributors</dt> |
| 9 | + <dd>@echeran</dd> |
| 10 | + <dt>First proposed</dt> |
| 11 | + <dd>2024-06-02</dd> |
| 12 | + <dt>Issues</dt> |
| 13 | + <dd><a href="https://github.com/unicode-org/message-format-wg/issues/782">#782</a></dd> |
| 14 | + <dd><a href="https://github.com/unicode-org/message-format-wg/issues/830">#830</a></dd> |
| 15 | + <dd><a href="https://github.com/unicode-org/message-format-wg/issues/831">#831</a></dd> |
| 16 | + <dt>Pull Requests</dt> |
| 17 | + <dd><a href="https://github.com/unicode-org/message-format-wg/pull/795">#795</a></dd> |
| 18 | + <dd><a href="https://github.com/unicode-org/message-format-wg/pull/804">#804</a></dd> |
| 19 | + <dt>Meeting Notes</dt> |
| 20 | + <dd><a href="https://github.com/unicode-org/message-format-wg/blob/main/meetings/2024/notes-2024-05-06.md">2024-05-06</a></dd> |
| 21 | + <dd><a href="https://github.com/unicode-org/message-format-wg/blob/main/meetings/2024/notes-2024-05-13.md">2024-05-13</a></dd> |
| 22 | + <dd><a href="https://github.com/unicode-org/message-format-wg/blob/main/meetings/2024/notes-2024-05-20.md">2024-05-20</a></dd> |
| 23 | + <dd><a href="https://github.com/unicode-org/message-format-wg/blob/main/meetings/2024/notes-2024-07-15.md">2024-07-15</a></dd> |
| 24 | + <dd><a href="https://github.com/unicode-org/message-format-wg/blob/main/meetings/2024/notes-2024-07-22.md">2024-07-22</a></dd> |
| 25 | + </dl> |
| 26 | +</details> |
| 27 | + |
| 28 | +## Objective |
| 29 | + |
| 30 | +Decide whether and what implementations "MUST" / "SHOULD" / "MAY" perform after a runtime error, regarding: |
| 31 | + |
| 32 | +1. information about error(s) |
| 33 | + - including, if relevant, the minimum number of errors for which such information is expected |
| 34 | +1. a fallback representation of the message |
| 35 | + |
| 36 | +## Background |
| 37 | + |
| 38 | +In practice, |
| 39 | +runtime errors happen when formatting messages. |
| 40 | +It is useful to provide information about any errors back to the callsite. |
| 41 | +It is useful to the end user to provide a best effort fallback representation of the message. |
| 42 | +Specifying the behavior in such cases promotes consistent results across conformant implementations. |
| 43 | + |
| 44 | +However, implementations of MessageFormat 2.0 will be faced with different constraints due to various reasons: |
| 45 | + |
| 46 | +* Programming language: the language of the implementation informs idiomatic patterns of error handling. |
| 47 | +In Java, errors are thrown and subsequently caught in `try...catch` block. |
| 48 | +In Rust, fallible callsites (those which can return errors) should return a `Result<T, Err>` monad. |
| 49 | +In both languages, built-in error handling assumes a singular error. |
| 50 | +* Environment constriants: as mentioned in [feedback from ICU4X](https://github.com/unicode-org/message-format-wg/issues/782#issuecomment-2103177417), |
| 51 | +ICU4X operates in low resource environments for which returning at most 1 error is desirable |
| 52 | +because returning more than 1 error would require heap allocation. |
| 53 | +* Programming conventions and idioms: in [feedback from ICU-TC](https://docs.google.com/document/d/11yJUWedBIpmq-YNSqqDfgUxcREmlvV0NskYganXkQHA/edit#bookmark=id.lx4ls9eelh99), |
| 54 | +they found over the 25 years of maintaining the library that there was more cost than benefit in additionally providing error information with a default best effort return value compared to just returning the default best effort value. |
| 55 | +The additional constraint in ICU4C's C++ style to return an error code rather than throwing errors using the STL further complicates the usefulness and likelihood to be used correctly by developers, especially during nested calls. |
| 56 | + |
| 57 | +> [!NOTE] |
| 58 | +> The wording in this document uses the word "signal" in regards to providing |
| 59 | +> information about an error rather than "return" or "emit" when referring to |
| 60 | +> a requirement that an implementation must at least indicate that an error has |
| 61 | +> occurred. |
| 62 | +> The word "signal" better accomodates more alternatives in the solution space |
| 63 | +> like those that only choose to indicate that an error occurred, |
| 64 | +> while still including those that additionally prefer to return the error |
| 65 | +> itself as an error object. |
| 66 | +> (By contrast, "return an error" implies that an error object will be thrown or |
| 67 | +> returned, and "emit an error" is ambiguous as to what is or isn't performed.) |
| 68 | +## Use Cases |
| 69 | + |
| 70 | +As a software developer, I want message formatting calls to signal runtime errors |
| 71 | +in a manner consistent with my programming language/environment. |
| 72 | +I would like error signals to include diagnostic information that allows me to debug errors. |
| 73 | + |
| 74 | +As a software developer, I sometimes need to be able to emit a formatted message |
| 75 | +even if a runtime error has occurred. |
| 76 | + |
| 77 | +As a software developer, I sometimes want to avoid "fatal" error signals, |
| 78 | +such as might occur due to unconstrained inputs, |
| 79 | +errors in translation of the message, |
| 80 | +or other reasons outside my control. |
| 81 | +For example, in Java, throwing an Exception is a common means of signaling an error. |
| 82 | +However, `java.text.NumberFormat` provide both throwing and non-throwing |
| 83 | +`parse` methods to allow developers to avoid a "fatal" throw of `ParseException` |
| 84 | +(if the exception were uncaught). |
| 85 | + |
| 86 | +As a MessageFormat implementer, I want to be able to signal errors in an idiomatic way |
| 87 | +for my language and still be conformant with MF2 requirements. |
| 88 | + |
| 89 | +## Accepted Design |
| 90 | + |
| 91 | +The following design was selected in #830. |
| 92 | + |
| 93 | +### MUST signal errors and MUST provide fallback |
| 94 | + |
| 95 | +* Implementations MUST provide a mechanism for signaling errors. There is no specific requirement for what form signaling an error takes. |
| 96 | +* Implementations MUST provide a mechanism for getting a fallback representation of a message that produces a formatting or selection error. Note that this can be entirely separate from the first requirement. |
| 97 | +* An implementation is not conformant unless it provides access to both behaviors. It is compliant to do both in a single formatting attempt. |
| 98 | + |
| 99 | +> In all cases, when encountering an error, |
| 100 | +> a message formatter MUST be able to signal an error or errors. |
| 101 | +> It MUST also provide the appropriate fallback representation of the _message_ defined |
| 102 | +> in this specification. |
| 103 | +
|
| 104 | +This alternative requires that an implementation provide both an error signal |
| 105 | +and a means of accessing a "best-effort" fallback message. |
| 106 | +This slightly relaxes the requirement of "returning" an error |
| 107 | +(to allow a locally-appropriate signal of the error). |
| 108 | + |
| 109 | +Under this alternative, implementations can be conformant by providing |
| 110 | +two separate formatting methods or functions, |
| 111 | +one of which returns the fallback string and one of which signals the error. |
| 112 | + |
| 113 | +Similar to the current spec text, |
| 114 | +this alternative requires implementations to provide useful information: |
| 115 | +both a signal that an error occurred and a best effort message. |
| 116 | +A downside to this alternative is that these requirements together assume that |
| 117 | +all implementations will want to pay the cost of constructing a representative mesage |
| 118 | +after the occurrence of an error. |
| 119 | + |
| 120 | +## Alternatives Considered |
| 121 | + |
| 122 | +### Current spec: require information from error(s) and a representative best effort message |
| 123 | + |
| 124 | +The current spec text says: |
| 125 | + |
| 126 | +> In all cases, when encountering a runtime error, |
| 127 | +> a message formatter MUST provide some representation of the message. |
| 128 | +> An informative error or errors MUST also be separately provided. |
| 129 | +
|
| 130 | +This alternative places constraints on implementations to provide multiple avenues of useful information (to the callsite and user). |
| 131 | + |
| 132 | +This alternative establishes constraints that would contravene the constraints that exist in projects that have implemented MF 2.0 (or likely will soon), based on: |
| 133 | +* programming language idioms/constraints |
| 134 | +* execution environment constraints |
| 135 | +* experience-based programming guidelines |
| 136 | + |
| 137 | +For example, in ICU, |
| 138 | +[the suggested practice](https://docs.google.com/document/d/11yJUWedBIpmq-YNSqqDfgUxcREmlvV0NskYganXkQHA/edit#bookmark=id.lx4ls9eelh99) |
| 139 | +is to avoid additionally returning optional error codes when providing best-effort formatted results. |
| 140 | + |
| 141 | +### MUST signal errors and SHOULD provide fallback |
| 142 | + |
| 143 | +* Implementations MUST provide a mechanism for signaling errors. There is no specific requirement for what form signaling an error takes. |
| 144 | +* Implementations SHOULD provide a mechanism for getting a fallback representation of a message that produces a formatting or selection error. Note that this can be entirely separate from the first requirement. |
| 145 | +* Implementations are conformant if they only signal errors. |
| 146 | + |
| 147 | +### SHOULD signal errors and MUST provide fallback |
| 148 | + |
| 149 | +* Implementations SHOULD provide a mechanism for signaling errors. There is no specific requirement for what form signaling an error takes. |
| 150 | +* Implementations MUST provide a mechanism for getting a fallback representation of a message that produces a formatting or selection error. Note that this can be entirely separate from the first requirement. |
| 151 | +* Implementations are conformant if they only provide a fallback representation of a message. |
| 152 | + |
| 153 | + |
| 154 | +### Error handling is not a normative requirement |
| 155 | + |
| 156 | +* Implementations are not required by MF2 to signal errors or to provide access to a fallback representation. |
| 157 | + - The specification provides guidance on error conditions; on what error types exist; and what the fallback representation is. |
| 158 | + |
| 159 | +> When encountering an error during formatting, |
| 160 | +> a message formatter MAY provide some representation of the message, |
| 161 | +> or it MAY provide an informative error or errors. |
| 162 | +> An implementation MAY provide both. |
| 163 | +
|
| 164 | +This alternative places no expectations on implementations, |
| 165 | +which supports the constraints we know now, |
| 166 | +as well as any possible constraints in the future |
| 167 | +(ex: new programming languages, new execution environments). |
| 168 | + |
| 169 | +This alternative does not assume or assert that some type of useful information |
| 170 | +(error info, representative message) |
| 171 | +will be possible and should be returned. |
| 172 | + |
| 173 | +### Alternate wording |
| 174 | + |
| 175 | +> When an error is encountered during formatting, |
| 176 | +> a message formatter can provide an informative error (or errors) |
| 177 | +> or some representation of the message or both. |
0 commit comments