<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Aug 18, 2017, at 1:09 PM, John McCall <<a href="mailto:rjmccall@apple.com" class="">rjmccall@apple.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class=""><br class="Apple-interchange-newline">On Aug 18, 2017, at 10:19 AM, Matthew Johnson <<a href="mailto:matthew@anandabits.com" class="">matthew@anandabits.com</a>> wrote:<br class=""><br class=""><br class=""><br class="">Sent from my iPad<br class=""><br class="">On Aug 18, 2017, at 1:27 AM, John McCall <<a href="mailto:rjmccall@apple.com" class="">rjmccall@apple.com</a>> wrote:<br class=""><br class=""><blockquote type="cite" class=""><blockquote type="cite" class="">On Aug 18, 2017, at 12:58 AM, Chris Lattner via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:<br class="">Splitting this off into its own thread:<br class=""><br class=""><blockquote type="cite" class="">On Aug 17, 2017, at 7:39 PM, Matthew Johnson <<a href="mailto:matthew@anandabits.com" class="">matthew@anandabits.com</a>> wrote:<br class="">One related topic that isn’t discussed is type errors. Many third party libraries use a Result type with typed errors. Moving to an async / await model without also introducing typed errors into Swift would require giving up something that is highly valued by many Swift developers. Maybe Swift 5 is the right time to tackle typed errors as well. I would be happy to help with design and drafting a proposal but would need collaborators on the implementation side.<br class=""></blockquote><br class="">Typed throws is something we need to settle one way or the other, and I agree it would be nice to do that in the Swift 5 cycle.<br class=""><br class="">For the purposes of this sub-discussion, I think there are three kinds of code to think about:<span class="Apple-converted-space"> </span><br class="">1) large scale API like Cocoa which evolve (adding significant functionality) over the course of many years and can’t break clients.<span class="Apple-converted-space"> </span><br class="">2) the public API of shared swiftpm packages, whose lifecycle may rise and fall - being obsoleted and replaced by better packages if they encounter a design problem. <br class="">3) internal APIs and applications, which are easy to change because the implementations and clients of the APIs are owned by the same people.<br class=""><br class="">These each have different sorts of concerns, and we hope that something can start out as #3 but work its way up the stack gracefully.<br class=""><br class="">Here is where I think things stand on it:<br class="">- There is consensus that untyped throws is the right thing for a large scale API like Cocoa. NSError is effectively proven here. Even if typed throws is introduced, Apple is unlikely to adopt it in their APIs for this reason.<br class="">- There is consensus that untyped throws is the right default for people to reach for for public package (#2).<br class="">- There is consensus that Java and other systems that encourage lists of throws error types lead to problematic APIs for a variety of reasons.<br class="">- There is disagreement about whether internal APIs (#3) should use it. It seems perfect to be able to write exhaustive catches in this situation, since everything in knowable. OTOH, this could encourage abuse of error handling in cases where you really should return an enum instead of using throws.<br class="">- Some people are concerned that introducing typed throws would cause people to reach for it instead of using untyped throws for public package APIs.<br class=""></blockquote><br class="">Even for non-public code. The only practical merit of typed throws I have ever seen someone demonstrate is that it would let them use contextual lookup in a throw or catch. People always say "I'll be able to exhaustively switch over my errors", and then I ask them to show me where they want to do that, and they show me something that just logs the error, which of course does not require typed throws. Every. Single. Time.<br class=""></blockquote><br class="">I agree that exhaustive switching over errors is something that people are extremely likely to actually want to do. I also think it's a bit of a red herring. The value of typed errors is *not* in exhaustive switching. It is in categorization and verified documentation.<br class=""><br class="">Here is a concrete example that applies to almost every app. When you make a network request there are many things that could go wrong to which you may want to respond differently:<br class="">* There might be no network available. You might recover by updating the UI to indicate that and start monitoring for a reachability change.<br class="">* There might have been a server error that should eventually be resolved (500). You might update the UI and provide the user the ability to retry.<br class="">* There might have been an unrecoverable server error (404). You will update the UI.<br class="">* There might have been a low level parsing error (bad JSON, etc). Recovery is perhaps similar in nature to #2, but the problem is less likely to be resolved quickly so you may not provide a retry option. You might also want to do something to notify your dev team that the server is returning JSON that can't be parsed.<br class="">* There might have been a higher-level parsing error (converting JSON to model types). This might be treated the same as bad JSON. On the other hand, depending on the specifics of the app, you might take an alternate path that only parses the most essential model data in hopes that the problem was somewhere else and this parse will succeed.<br class=""><br class="">All of this can obviously be accomplished with untyped errors. That said, using types to categorize errors would significantly improve the clarity of such code.<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Recall that we're not talking about error values themselves being untyped, i.e. just strings or something. They still have arbitrary typed structure; you can have an enum of network errors that claims to tell you all the ways that an API can fail due to network errors, and that's still extremely informative. It's just that the typing is dynamic at the highest level (and only there, subject to the definition of your error types). You have to ask whether it failed specifically because of a network error, and you have to handle the possibility that it failed for some other reason.</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class="">More importantly, I believe that by categorizing errors in ways that are most relevant to a specific domain a library (perhaps internal to an app) can encourage developers to think carefully about how to respond.<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Absolutely.</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class="">Bad error handling is pervasive. The fact that everyone shows you code that just logs the error is a prime example of this. It should be considered a symptom of a problem, not an acceptable status quo to be maintained. We need all the tools at our disposal to encourage better thinking about and handling of errors. Most importantly, I think we need a middle ground between completely untyped errors and an exhaustive list of every possible error that might happen. I believe a well designed mechanism for categorizing errors in a compiler-verified way can do exactly this.<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">If that middle ground is just "here's a list of errors that I, as an API writer, want you to specifically be aware of that this might throw", that's essentially just documentation.</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class="">In many respects, there are similarities to this in the design of `NSError` which provides categorization via the error domain. This categorization is a bit more broad than I think is useful in many cases, but it is the best example I'm aware of.<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">The design of NSError is essentially the design of Error. There are arbitrary, extensible categories (error types) which can each be broken down into specific failures (cases of those types), but the type of the standard container itself doesn't restrict what categories might be present.</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class="">The primary difference between error domains and the kind of categorization I am proposing is that error domains categorize based on the source of an error whereas I am proposing categorization driven by likely recovery strategies. Recovery is obviously application dependent, but I think the example above demonstrates that there are some useful generalizations that can be made (especially in an app-specific library), even if they don't apply everywhere.<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">I'm not sure that recoverability is a generic property in that way, but it's an interesting idea.</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""></div></blockquote><div><br class=""></div><div>It’s not *completely* general, but within a bounded domain it is certainly possible to make general decisions about how you intend to recover in the majority of specific cases.</div><br class=""><blockquote type="cite" class=""><div class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class="">Sometimes we then go on to have a conversation about wrapping errors in other error types, and that can be interesting, but now we're talking about adding a big, messy feature just to get "safety" guarantees for a fairly minor need.<br class=""></blockquote><br class="">I think you're right that wrapping errors is tightly related to an effective use of typed errors. You can do a reasonable job without language support (as has been discussed on the list in the past). On the other hand, if we're going to introduce typed errors we should do it in a way that *encourages* effective use of them. My opinion is that encouraging effect use means categorizing (wrapping) errors without requiring any additional syntax beyond the simple `try` used by untyped errors. In practice, this means we should not need to catch and rethrow an error if all we want to do is categorize it. Rust provides good prior art in this area.<br class=""></blockquote><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">Yes, the ability to translate errors between domains is definitely something we could work on, whether we have typed errors or not.</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""></div></blockquote><div><br class=""></div><div>I’m glad to hear that! :) To be clear, I’m not stuck on typed errors as the only way to solve this problem, but do have specific use cases in mind that I would like to see addressed one way or another.</div><div><br class=""></div><div>The primary goal for me personally is to factor out and centralize code that categorizes an error, allowing catch sites to focus on implementing recovery instead of figuring out what went wrong. Here’s some concrete sample code building on the example scenario above:</div><div><br class=""></div><div><div>enum NetworkError: Error {</div><div><div> case noNetwork(Error, URLResponse)</div><div> case serverFailure(Error, URLResponse)</div><div> case badRequest(Error, URLResponse)</div><div> case authentication(Error, URLResponse)</div><div><br class=""></div><div> var response: URLResponse { // switch }</div><div> var underlyingError: Error { // switch }</div><div><br class=""></div><div> init(error: Error, response: URLResponse) {</div><div> // inspect error and response and categorize appropriately</div><div> }</div></div><div>}</div><div><br class=""></div><div><div>enum ParsingError: Error {</div><div><div> case deserialization(Error, Data)</div><div> case decoding(Error, Data)</div><div><br class=""></div><div><div> var data: Data { // switch }</div><div> var underlyingError: Error { // switch }</div></div><div><br class=""></div><div> init(error: Error, data: Data) {</div><div> // inspect error and response and categorize appropriately</div><div> // this assumes errors reported by the decoder provide sufficient information to distinguish the errors as desired</div><div> // prior to Codable the first case would come from NSJSONSerialization and the other from the dictionary to model conversion</div><div> }</div></div><div>}</div></div></div><div><br class=""></div><div>enum NestedAPIRequestError: Error {</div><div> case network(NetworkError)</div><div> case parsing(ParsingError)</div><div><br class=""></div><div> var underlyingError: Error { // switch }</div><div>}</div><div><br class=""></div><div>— or</div><div><br class=""></div><div><div>enum FlatAPIRequestError: Error {</div><div><div> case noNetwork(Error, URLResponse)</div><div> case serverFailure(Error, URLResponse)</div><div> case badRequest(Error, URLResponse)</div><div> case authentication(Error, URLResponse)</div><div><div> case deserialization(Error, Data)</div><div> case decoding(Error, Data)</div></div></div><div><br class=""></div><div> var underlyingError: Error { // switch }</div><div>}</div></div><div><br class=""></div><div>The important thing to note is that the categorization algorithms are driven by the intended recovery strategy and relies on knowledge about the domain. The algorithm itself is selected by the dynamic context as the error propagates. In some cases the underlying error itself is sufficient for categorization, but in other cases contextual data is also used (notably the URLResponse). I recall looking into a Boost error handling library Dave Abrahams pointed me to (early this year?) whose intent was to attach dynamic data to an error as it flows up the stack. That was a very interesting idea and seems especially powerful when coupled with this kind of error categorization.</div><div><br class=""></div><div>It may or may not be worthwhile to have the ability to determine that “other” / “unknown” errors fall into one of the categories. It is certainly the case that many contexts will require an “other" / “unknown” category. I wouldn’t feel too bad about a solution that always included an unbounded case, at least in async code. That would still be a huge step forward from where we are now. On the other hand, there are cases where we are in full control of all errors that are thrown and can ensure completeness of the categorization. Most notably, it could be handy to have exhaustive error categorization when using (abusing?) error handling for control flow in things like parsers, test code, etc.</div><div><br class=""></div><div>Stepping away from specific solutions, what I am personally looking for is the following:</div><div><br class=""></div><div>1. A way to factor out these categorization algorithms.</div><div>2. A way to have them invoked without boilerplate as errors propagate.</div><div>3. A way to have documentation in the source code that is compiler verified regarding the categorization in effect at a function boundary.</div><div>4. A way to match errors based on this categorization (included nested categorization in the case of NestedAPIRequestError).</div><div><div><br class=""></div><div>If we come up with a way to address these goals without using the type system I’m sure I will be happy! :) Types just feel like the most natural / obvious solution.</div><div><br class=""></div><div>With the above in mind, what are your thoughts on the four goals outlined above? Do you have any thoughts on how they might be addressed in a way that doesn’t use the type system?</div><div><br class=""></div><div>Matthew</div></div><br class=""><blockquote type="cite" class=""><div class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">John.</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class="">Programmers often have an instinct to obsess over error taxonomies that is very rarely directed at solving any real problem; it is just self-imposed busy-work.<br class=""></blockquote><br class="">I agree that obsessing over intricate taxonomies is counter-productive and should be discouraged. On the other hand, I hope the example I provided above can help to focus the discussion on a practical use of types to categorize errors in a way that helps guide *thinking* and therefore improves error handling in practice.<br class=""><br class=""><blockquote type="cite" class=""><br class=""><blockquote type="cite" class="">- Some people think that while it might be useful in some narrow cases, the utility isn’t high enough to justify making the language more complex (complexity that would intrude on the APIs of result types, futures, etc)<br class=""><br class="">I’m sure there are other points in the discussion that I’m forgetting.<br class=""><br class="">One thing that I’m personally very concerned about is in the systems programming domain. Systems code is sort of the classic example of code that is low-level enough and finely specified enough that there are lots of knowable things, including the failure modes.<br class=""></blockquote><br class="">Here we are using "systems" to mean "embedded systems and kernels". And frankly even a kernel is a large enough system that they don't want to exhaustively switch over failures; they just want the static guarantees that go along with a constrained error type.<br class=""><br class=""><blockquote type="cite" class="">Beyond expressivity though, our current model involves boxing thrown values into an Error existential, something that forces an implicit memory allocation when the value is large. Unless this is fixed, I’m very concerned that we’ll end up with a situation where certain kinds of systems code (i.e., that which cares about real time guarantees) will not be able to use error handling at all. <br class=""><br class="">JohnMC has some ideas on how to change code generation for ‘throws’ to avoid this problem, but I don’t understand his ideas enough to know if they are practical and likely to happen or not.<br class=""></blockquote><br class="">Essentially, you give Error a tagged-pointer representation to allow payload-less errors on non-generic error types to be allocated globally, and then you can (1) tell people to not throw errors that require allocation if it's vital to avoid allocation (just like we would tell them today not to construct classes or indirect enum cases) and (2) allow a special global payload-less error to be substituted if error allocation fails.<br class=""><br class="">Of course, we could also say that systems code is required to use a typed-throws feature that we add down the line for their purposes. Or just tell them to not use payloads. Or force them to constrain their error types to fit within some given size. (Note that obsessive error taxonomies tend to end up with a bunch of indirect enum cases anyway, because they get recursive, so the allocation problem is very real whatever we do.)<br class=""><br class="">John.</blockquote></blockquote></div></blockquote></div><br class=""></body></html>