[swift-evolution] do try catch?

John McCall rjmccall at apple.com
Fri Dec 18 16:10:13 CST 2015


> On Dec 7, 2015, at 8:30 PM, Liam Butler-Lawrence via swift-evolution <swift-evolution at swift.org> wrote:
> Hi Kame,
> 
> Thanks for the work you put into this! I’ll give my thoughts on each proposed syntax:
> 
>> // First syntax:
>>     guard let
>>         bar = bar,  // Has to be non-nil
>>         try foo("Hello"),   // Has to not throw an error
>>         x = try qux()
>>         where bar > 10
>>     else {    // Has to not throw an error
>>         return  // Bar or baz was nil
>>     } catch Error.Some {
>>         return  // Some Error occured
>>     } catch {
>>         return  // Another Error occured
>>     }
>>     
>>     // `else` has to be there for optional, `catch` for errors
>>     guard try foo("Hello"), let x = try qux() where x < 10 catch Error.Some {
>>         return
>>     } catch {
>>         return
>>     }
>>     
>>     // Results can be ignored; catch can be on new line
>>     guard let
>>         _ = try foo("Hello"),
>>         _ = try qux()
>>     catch Error.Some {  // Not 100% beautiful
>>         return
>>     } catch {
>>         return
>>     }
> 
> 
> This is comprehensive and seems (to me, anyway!) like it could definitely work. My only concern is that the similar-but-different syntaxes for the different optional/try combinations could be a bit confusing. I see the following three unique syntaxes in your proposal:
> 
>>     guard let x = y, try z(a) else { } catch E { }... catch { }
>>     guard let x = try z(a) else { } catch E { }... catch { }
>>     guard try z(a) catch E { }... catch { }
> 
> 
> That’s not even considering where conditions, or chaining more than a single optional and try together in a single guard expression. 

This proposal packs an awful lot into a single “guard” statement, but that might be okay; it’s just something that I personally am not totally comfortable with.

The larger problem that I see is that this changes the semantic behavior of “guard” quite a bit.  Normally, in something like:

  guard let x = foo(),
        bar()
    else { … }

these clauses are both expected to be conditional: that is, foo() is expected to return an optional type, bar() is expected to return a Bool, etc.  The guard protects against the exceptional conditions.  But this isn’t really what you want, because the exceptional condition you’re looking to guard against is whether the expression threw.  Thus, in the corresponding example:

  guard let x = try foo(),
        try bar()
    catch { … }
  
it should at the very least be acceptable for foo() to return a non-optional type, and if it doesn’t, it’s debatable whether you really want to unwrap it; and similarly, it might be reasonable for bar() to return Void, e.g.:

  guard try registerUser()
    catch { … }

Part of this is just the original sin that “if let” and “guard let” aren't very composable.  For example, you run into a very similar problem with normal “guard” just by trying to bind a non-optional value between two other conditions, e.g.:
  guard let resolver = factory.currentResolver,
        let numResolved = resolver.resolvedEntityCount,
        numResolved < maxResolutionCount
    else { … }

However, this new pattern for guard really exacerbates the problem, both because it’s so common to have functions with non-optional results that throw errors, and because even when the function has an optional result, it’s ambiguous whether you really want to simultaneously unwrap it.  In other words, there’s too much magic in this syntax, and it seems to be colliding.

One possible solution is to say that “guard let" only unwraps results if there’s an else clause.  (What happens with “guard try foo()” in this case?)  But that means that adding and removing an else clause has very subtle and hard-to-explain semantic effects on the semantics of “guard”.  I’m tempted to say that we just shouldn’t allow the combination of an else clause and catch clauses, but that’s just begging for people to ask for the combination, at which point we’ll have codified two incompatible models for the statement.

John.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151218/990d689d/attachment.html>


More information about the swift-evolution mailing list