I’m bumping this post in case you missed it Brent. I would find any comments you have on the differences between our approaches very interesting. Thanks!
> On Dec 17, 2015, at 10:36 AM, Matthew Johnson via swift-evolution > <[email protected]> wrote: > > Brent, thanks for sharing this. It’s interesting that we independently came > up with such similar approaches. That seems to indicate that it is > definitely worthy of consideration. > > IMO your proposal is actually three proposals. I obviously think “catching > functions” might have a chance for consideration right now. I also think > @once is a very good idea and probably has a good chance for consideration as > an independent proposal. Obviously async is going to have to wait. > > I’m going to comment on differences between our approaches to catching > functions and include the rationale for my decisions. I hope you will do the > same and maybe we can reach a consensus on the best approach. > >> A function type can be marked as `catching`. >> >> catching T -> U > > I prefer the T -> U catches syntax as it more closely matches the syntax for > throws, but the syntax is the least important part of this to me and I would > be happy with anything sensible. > >> Catching functions must be exhaustive (i.e. must include a plain `catch` >> block), with two exceptions to be described later. > > Rather than requiring this I introduced an @exhaustive attribute that can be > specified when required, as well as the ability of the caller to find out > whether the error was handled or not. I did this partly because of the > comparability use case and partly because it affords more flexibility without > losing the exhaustive behavior when that is necessary. > >> Catch blocks have the same return type as the regular block of their >> function. For instance, the catch blocks of a `catching Void -> Int` must >> return `Int`s. If the function is marked `throws`, then the catch blocks can >> `throw`. >> >> func convertOnlyCloudErrors() throws -> String { >> return “OK” >> } >> catch let error as CKErrorCode { >> return error.description >> } >> catch { >> throw error >> } > > Did you intend to mark this function as `catching`? I’ll assume so as it > includes top level `catch` clauses. > > This approach is reasonable, but I’m interested in hearing what you think of > the other alternative I explored which goes hand-in-hand with non-exhaustive > catching functions. > > >> Here’s the first exception to catch exhaustiveness: a `catching throws` >> function has an implicit `catch { throw error }` block added if necessary. >> So that second catch block in the previous example is redundant. > > I don’t like this. I think it is better to keep things explicit. It would > also preclude non-exhaustive `catching` functions which I think have > interesting use cases. > >> >> To call the function normally, just…call it normally. >> >> foo() >> cloudKitQueryOp.queryCompletionBlock!(cursor) >> >> To send an error to it, use one of these: >> >> foo(throw error) >> foo(try someOperationThatMightFail()) // unconditionally >> calls foo() with the result, whether error or datum >> foo(try? someOperationThatMightFail()) // if an error is >> thrown, calls foo with the error and returns nil; if not, returns the result >> of the operation without calling foo >> >> I’m not totally satisfied with this syntax, and we should probably try to >> come up with something better. BUT NOT RIGHT NOW. Bikeshedding can wait. > > I don’t mean to bikeshed but I do think this particular syntax has serious > problems: > > func bar() throws { > // in both cases, should the error be thrown or caught by foo? > foo(throw error) > foo(try someOperationThatMightFail()) > } > > It might be possible to define this problem away, but even then you would not > know the answer without knowing the signature of `foo`. That is really bad > for readability. > > What do you think of the syntax I used, which is similar to yours while > avoiding these issues? > > foo(catch error) > > >> One issue with this is the question of whether a `throw` or non-optional >> `try` with a catching function implicitly `return`s immediately after >> calling the catching function. My current thinking is that it does *not* >> cause an immediate return, so you can come up with a return value yourself. >> But this is not entirely satisfying. > > This is only a problem because your syntax overloaded the existing throw and > try keywords and because of that introduced semantic confusion. > >> To Objective-C, a catching function is a block with the same parameters, >> only nullable, followed by a nullable NSError. If there are no parameters, >> then an initial BOOL parameter is inserted. >> >> @property (nonatomic, copy, nullable) void >> (^queryCompletionBlock)(CKQueryCursor * __nullable cursor, NSError * >> __nullable operationError); >> var queryCompletionBlock: (catching CKQueryCursor -> Void)? > > Glad to see you address Objective-C interop. I hadn’t considered that yet. > > Matthew > _______________________________________________ > swift-evolution mailing list > [email protected] > https://lists.swift.org/mailman/listinfo/swift-evolution _______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
