Not sure what you mean here. A guard/catch would allow me to handle the error in the catch, something that (of course) cannot be done with "try?", so guard/else with "try?" is not a solution. And of course returning in the catch side of a do/catch is like returning in the else side of a if/else, but that's what "guard" is about, so I probably didn't understand what's your point here.
Elviro > Il giorno 11 lug 2017, alle ore 01:10, Christopher Kornher <ckorn...@me.com> > ha scritto: > > FYI this works today in Xcode 9.0 beta 2 playgrounds: > > ``` > class X { > init() throws {} > > func foo() { > print( "Things succeeded" ) > } > } > > func bar() throws -> X { return try X() } > > > func f() > { > guard let x1:X = try? X(), let x2:X = try? bar() else { > print( "Things failed ") > return > } > > x1.foo() > x2.foo() > } > > f() // works > ``` > > So the only unhandled case is a non-returning throwing function or init: > > ``` > class X { > init() throws {} > > func foo() { > print( "Things succeeded" ) > } > } > > func bar() throws{ let _ = try X() } > > > func f() > { > do { > try bar() > } catch { > return > } > > guard let x:X = try? X() else { > print( "Things failed ") > return > } > > x.foo() > } > > f() // works > ``` > > Having to call a throwing, Void method before performing the rest of a > function seems like an edge case to me > > >> On Jul 10, 2017, at 1:45 AM, Elviro Rocca via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote: >> >> This is not a sugar proposal, in the same way as "guard" is not syntactic >> sugar, because it requires exiting the scope on the else branch, adding >> expressive power and safety to the call: also, the sugary part is pretty >> important because it avoids nested parentheses and very clearly states that >> if the guard condition is not fulfilled, the execution will not reach the >> next lines of code. Guard is useful to push the programmer to at least >> consider an early return instead of branching code paths, to achieve better >> clarity, readability and lower complexity, and I suspect is one of the best >> Swift features for many people. >> >> Also, the case that the proposal aims to cover is not an edge case at all >> for a lot of people, including me. Rethrowing an error is something that I >> almost never do, and I consider the "umbrella" do/catch at the top of the >> call stack an anti-pattern, but I understand that many people like it and >> I'm not arguing against it. I am arguing in favor of having options and not >> pushing a particular style onto programmers, and for my (and many people's) >> style, a guard/catch with forced return is an excellent idea. In fact you >> seem to agree on the necessity of some kind of forced-returnish catch but >> your elaborations don't seem (to me) much better than the proposal itself. >> >> Dave DeLong raised the point of weird behavior in the case of a function >> like: >> >> >> func doSomething() throws → Result? { … } >> >> >> In this case, what would the type of x be? >> >> >> guard let x = try doSomething() catch { /// handle and return } >> >> >> Simple, it would be Optional<Result>. I don't find this confusing at all, >> and if the idea that just by seeing "guard let" we should expect a >> non-Optional is somehow diffused, I think it's better to eradicate it. >> >> First of all, if I'm returning an optional from a throwing function, it's >> probably the case that I want the Optional to be there in the returned >> value: the only reason why I would consider doing that is if the semantics >> of Optional are pretty meaningful in that case. For example, when parsing a >> JSON in which I expect a String or null to be at a certain key: >> >> >> extension String: Error {} >> >> func parseString(in dict: [String:Any], at key: String) throws -> String? { >> guard let x = dict[key] else { throw "No value found at '\(key)' in >> \(dict)" } >> if let x = x as? String { return x } >> if let x = x as? NSNull { return nil } >> throw "Value at '\(key)' in \(dict) is not 'string' or 'null" >> } >> >> >> Thus, if I'm returning an Optional from a throwing function it means that I >> want to clearly distinguish the two cases, so they shouldn't be collapsed in >> a single call: >> >> >> guard let x = try doSomething() catch { /// handle and return } >> guard let x = x else { /// handle and return } >> >> >> Also, if a function returns something like "Int??", a guard-let (or if-let) >> on the returned value of that function will still bind an "Int?", thus >> unwrapping only "one level" of optional. If-let and guard-let, as of today, >> just unwrap a single optional level, an do not guaranteed at all that the >> bound value is not optional. >> >> To me guard-let (like if-let) is basically sugar for monadic binding for >> Optionals, with the additional expressivity granted by the forced return. I >> would love to see the same monadic binding structure applied to throwing >> functions. >> >> >> >> Elviro >> >> >> >>> Il giorno 09 lug 2017, alle ore 01:16, Christopher Kornher via >>> swift-evolution <swift-evolution@swift.org >>> <mailto:swift-evolution@swift.org>> ha scritto: >>> >>> Thanks for you considerate reply. My concern over the proliferation of >>> “sugar proposals” is a general one. This proposal has more merit and >>> general utiliity than many others. I have never used a throwing function in >>> a guard statement that was not itself in a throwing function, but I can see >>> that it could possibly be common in some code. Wrapping a guard statement >>> and all the code that uses variables set in the guard in a do/catch is >>> sub-optimal. >>> >>>> On Jul 8, 2017, at 4:16 PM, Benjamin Spratling via swift-evolution >>>> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote: >>>> >>>> >>>> >>>> I’ve read your email, but haven’t digested it fully. One thing I agree >>>> with is that most functions which call throwing functions don’t actually >>>> use a do…catch block, but instead are merely marked “throws” and the error >>>> is propagated back through the stack. Once I seriously started coding >>>> functions with errors, I realized I almost always wanted my errors to >>>> reach my view-controller or my business logic so I could present separate >>>> UI if a real error occurred, and often my error message depended on the >>>> details of the error instance. >>>> >>>> >>>> >>>> I disagree with your conclusion on this point. >>>> The “guard” syntax is specifically designed to achieve early return (and >>>> placing code associated with early return at the point where it happens) >>>> and cleanly installing the returned value into the surrounding scope. So >>>> far it has been used to achieve early return only with optionals, true. >>>> But is that inherent to ‘guard’, or is it merely because that’s the only >>>> way it has been used? The guard does set variables that are needed in the >>>> body of the function, and that’s exactly why using guard with values >>>> returned from throwing functions makes so much sense, because it does >>>> exactly the same thing in a general sense. The “do”…”catch” structure is >>>> intentionally designed differently, to place the “happy path” in one place >>>> and place the returns in another place. I think with guard/else, we’re >>>> seeing developers who can handle less cognitive loading find it easier to >>>> reason about early return than grouping failures after the happy path. >>>> This proposal hopes to introduce that better language architecture to the >>>> catching of errors. >>>>> On Jul 8, 2017, at 4:08 PM, Christopher Kornher <ckorn...@me.com >>>>> <mailto:ckorn...@me.com>> wrote: >>>>> >>>>> I am opposed to this proposal because it muddies up the language to >>>>> support what is essentially an edge case. The standard way to exit a >>>>> function early because an exception is thrown is to make the function >>>>> itself throw, if it is part of a larger operation. The addition of a few >>>>> lines of try/catch code is not a great burden and makes the termination >>>>> of an an exception very clear. >>>>> `guard` statements are generally used to set variables that are needed in >>>>> the body of a function. Using them to save a few lines of exception >>>>> handing code is a very different use. There is no need to mix two >>>>> relatively clean syntaxes for a few edge cases and increase cognitive >>>>> load one more time, >>> >>> All catches don’t have to exit the outer scope, so using guard only handles >>> a subset >>> >>> It think that creating the terse try/catch for simple cases has multiple >>> advantages: >>> >>> 1) I think that it addresses your desire for a simple way to use >>> throwing functions easily in guard statements. >>> >>> 2) It avoids having to change the guard syntax to accomplish this >>> >>> 3) It is useful for handling simple one line try/catch constructs in >>> less space in a way that should not seem too foreign to Swift developers. >>> >>> 4) It simplifies code that currently uses nested do/try/catch >>> constructs. Even though this is rare, it introduces significant “rightward >>> drift”. >>> >>> 5) It can used to return early from void throwing functions easily. >>> e.g. : >>> >>> ``` >>>> guard try foo( ) catch { return } >>> ``` >>> >>> Multiple void throwing functions would probably be better handled by a >>> do/catch block, but there is no danger of needing values from these >>> functions because there are none: >>> >>> ``` >>>> do { >>>> try fn1() >>>> try fn2() >>>> } catch { >>>> // keep going, return or call a non-returning function, since >>>> throw is already handled by declaring a throwing enclosing function. >>>> // No varibles are needed by the outer block because none are >>>> set >>>> // So it is not clearly a guard-like statement >>>> } >>> ``` >>> >>> I did not think of this before, but perhaps we could allow `do` to be >>> replaced with `guard`, thereby allowing values to escape to the outer >>> scope, while still ensuring an early exit: >>> >>> ``` >>>> guard { >>>> try fn1() >>>> try fn2() >>>> let x = fn3() >>>> } catch { >>>> // Must exit >>>> } else { >>>> // Must exit >>>> } >>> ``` >>> I am not sure that “leaky” braces are a good idea, so perhaps some other >>> character could be used to indicate a non-scope or whatever you want to >>> call it: >>> >>> ``` >>>> guard <your favorite character here> >>>> try fn1() >>>> try fn2() >>>> let x = fn3() >>>> <another favorite character here> catch { >>>> // Must exit >>>> } else { >>>> // Must exit >>>> } >>> ``` >>> This would make the language even harder to read, so just using braces is >>> probably a better idea. >>> >>> This would change the guard syntax slightly, but is a straightforward >>> extrapolation of do/catch and guard, I think. Of course, this could replace >>> the existing guard syntax entirely and its use of semicolons, if we want to >>> go that far… >>> >>> Allowing this syntax only if one of the expressions throws is possibly a >>> good backward-compatible solution that would avoid redundant guard syntaxes. >>> >>> Anyway there are lot of possibilities here. We are not forced to extend the >>> guard statement as it exists today. The current guard statement syntax was >>> quite controversial when it was introduced and extending it may not be the >>> best option to do what you want. >>> >>> - Chris >>> >>> >>> >>> >>> >>> _______________________________________________ >>> swift-evolution mailing list >>> swift-evolution@swift.org <mailto:swift-evolution@swift.org> >>> https://lists.swift.org/mailman/listinfo/swift-evolution >>> <https://lists.swift.org/mailman/listinfo/swift-evolution> >>>> >>>> -Ben Spratling >>>> >>>> _______________________________________________ >>>> swift-evolution mailing list >>>> swift-evolution@swift.org <mailto:swift-evolution@swift.org> >>>> https://lists.swift.org/mailman/listinfo/swift-evolution >>>> <https://lists.swift.org/mailman/listinfo/swift-evolution> >> >> _______________________________________________ >> swift-evolution mailing list >> swift-evolution@swift.org <mailto:swift-evolution@swift.org> >> https://lists.swift.org/mailman/listinfo/swift-evolution >
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution