5 ms·
I'm not familiar with Swift, anyone already know how typed throws hold up? Checked exceptions are pretty universally seen as a mistake in Java [1] while ADT à l
by dtech 2y ago
I'm not familiar with Swift, anyone already know how typed throws hold up? Checked exceptions are pretty universally seen as a mistake in Java [1] while ADT à la Result are generally perceived better.
[1] See e.g. https://literatejava.com/exceptions/checked-exceptions-javas-biggest-mistake/ https://literatejava.com/exceptions/checked-exceptions-javas..., but also Java 8+ API's moving away from them.
- deleted 2y ago[deleted]
- airspeedswift 2y agoYou can read about the trade-offs in the language proposal here: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0413-typed-throws.md https://github.com/swiftlang/swift-evolution/blob/main/propo... In particular: > Even with the introduction of typed throws into Swift, the existing (untyped) throws remains the better default error-handling mechanism for most Swift code. The section "When to use typed throws" describes the circumstances in which typed throws should be used.
- brantonb 2y agoI think your link got cut off. Here’s the direct link to the section on when to use typed throws. I hadn’t read this before, and it changes how I’ll approach them. Thanks for pointing it out! https://github.com/swiftlang/swift-evolution/blob/main/proposals/0413-typed-throws.md https://github.com/swiftlang/swift-evolution/blob/main/propo...
- nielsbot 2y agoThrows in Swift are not traditional exceptions. A throwing function in Swift is actually a function that can return an error instead of a result. This is hidden by the language. So something like `func foo() throws -> Result` Is actually `func foo() -> Result | Error` The compiler also forces you to handle any returned errors using `try`. So to call our example `foo`, you'd do: `let result = try foo()` You must either handle any throws error or include this call in an enclosing throwing function.
- meindnoch 2y ago>Throws in Swift are not traditional exceptions. A throwing function in Swift is actually a function that can return an error instead of a result. This is hidden by the language. Implementation detail. The two features are equivalent.
- astrange 2y agoUsing the normal return path vs. nonlocal returns is, I think, not equivalent unless you have a GC. Otherwise you need all that "exception safe code" stuff. But the main difference is it's not hidden by the language; you have to 'try' any method that can return an error. Straight-line control flow in an imperative language is a good thing IMO. …but too bad about those defer statements.
- meindnoch 2y ago>Using the normal return path vs. nonlocal returns is, I think, not equivalent unless you have a GC. I will repeat, whether exceptions are implemented as "nonlocal returns" (like setjmp/longjmp with stack unwinding) or as syntax sugar with sum return types, is completely irrelevant; an implementation detail. The generated machine code is different, but the behavior, the user experience is exactly the same. >Otherwise you need all that "exception safe code" stuff. In both cases, you need to write "exception safe code". Example of unsafe code in Java (a language that implements exceptions as non-local returns): void bar() throws Exception { ... } void foo() throws Exception { mutex.lock(); bar(); mutex.unlock(); } Example of unsafe code in Swift (a language that transforms errors into sum return types): func bar() throws { ... } func foo() throws { mutex.lock() try bar() mutex.unlock() } >But the main difference is it's not hidden by the language; you have to 'try' any method that can return an error. Straight-line control flow in an imperative language is a good thing IMO. …but too bad about those defer statements. Whether the language makes you prefix throwing calls with "try" is completely orthogonal to how they're implemented (nonlocal return vs sum return type). It's just a matter of syntax.
- iainmerrick 2y agoPretty universally seen as a mistake by those people who see them as a mistake. :)
- w10-1 2y agoSwift throws are results, but now with specific and generic and specializable types. To illustrate, Swift has a nice `rethrows` feature that helps with function composition. If your function takes a function parameter that can throw, it can use 'rethrows' to say "I only throw if this parameter does". Then when passed a function that doesn't throw, your function need not be invoked with `try`. This plays nicely with generics over throwing type, since the bounds propagate back to the function type. If the function parameter only throws a given type, that's what the function will throw. Also helpful for reducing error boilerplate, `try` has the convenience form `try?` which means "just swallow the exception and return nil", and applies to a whole chain: `let f = try? this() ?? that() ?? "skip"` means f will be the result of either (throwing) function or a literal otherwise.
- dep_b 2y agoUsed typed throws for a bit and I like them. I remember from long ago the Java implementation forcing me to catch them but in Swift it’s just a bit of extra compiler-enforced documentation about what and what not to expect in terms of errors.
- wiseowise 2y agoChecked exceptions are universally seen as a mistake in Java* * - according to a couple of loudmouths on the internet
- dtech 2y agoAnd the designers and the Java stdlib itself, seeing as it's pretty much all runtime exceptions in everything introduced in Java 8 and later Also JVM guest languages like Kotlin and Scala treat all exceptions like runtime.
- yadaeno 2y agoChecked exceptions with lambdas are a nightmare from what I remember.
- bigstrat2003 2y agoChecked exceptions are in no way universally seen as a mistake. I thought, and still think, that they are a great feature of Java.
- serial_dev 2y agoI never understood why checked exceptions “are bad”, but Result types “are good”. To me they feel like conceptually the same idea.
- MBCook 2y agoIt’s often just the boilerplate. As a Java dev people often end up ignoring it and changing everything to “throws Exception” to avoid having to list 4 exception types all over a call stack. Or they catch and wrap everything in some CustomSysException type so they only have to list one type and it’s not Exception, but then that’s really the same thing isn’t it? I think it’s kind of a combination of not dealing with things and throwing them up the stack combined with too many exception types and maybe using exceptions when a result type would just be easier.
- jcparkyn 2y agoThe real answer IMO is how they (don't) integrate with generics, first-class functions, and the type system in general. If you try using a checked function inside a stream() call you'll know exactly what I mean. Yes, it's technically possible to make a "functional interface" with a fixed number of checked exceptions, but in practice it's a huge PITA and most functions just don't allow checked exceptions at all. Compare to ATDs, where any generic function taking a T can also be used with Result<T> exactly the same. (Not a perfect comparison, but there are lots of other scenarios where ATDs just compose better)
- astrange 2y agoIt's useful to have errors which are less typed than your "actual" results, because if you write a library then you don't want every possible error to be part of your API. If you do, and you call some other library, then either you have to swallow its errors or commit to having all of its error APIs be part of yours too. And in the end many errors can't be handled automatically, the best you can do is just show them to the user.
- pjmlp 2y agoMostly by Java haters, that even miss the point checked exceptions appeared first in CLU, Modula-3 and C++ before Java was even an idea. Forced checks on sum types with automatic unwinding are another way of doing checked exceptions, that apparently those haters love so much.