[swift-evolution] Proposal: Add implicit/default else-behaviour for the guard statement

Vester Gottfried vester.gottfried at gmail.com
Wed Dec 16 16:36:52 CST 2015


I just skipped through 200+ guard statements that return Void, nil or a
value and no statement was inside a scope that can be exited with break.

I am also thinking about the proposals regarding default values to return,
but I am not sure if this would even be necessary.  In my case 80% of all
guard statements end with "else { return }" or "else { return nil }".

On Wed, Dec 16, 2015 at 11:20 PM, Etan Kissling via swift-evolution <
swift-evolution at swift.org> wrote:

> If guard defaults to something context-dependent, it's also
> counterintuitive.
>
>
> Me personally is fine with guard x > 0 returning from the function in this
> case.
>
> I use guard mainly as a glorified assert that allows safe exit from the
> function instead of crashing the program on fail.
> If you think about it that way, it's perfectly reasonable that it returns
> in all cases.
>
>
>
> On the other hand, the implicit default else behaviour could only trigger
> if there is no outer scope that can be exited with break.
> Maybe OP could post additional statistics of the number cases where "guard
> ... else { return }" is used inside a breakable scope.
>
>
> Etan
>
>
>
>
>
> On 16 Dec 2015, at 23:15, Vinicius Vendramini <vinivendra at gmail.com>
> wrote:
>
> Bringing up a possible edge case:
>
> func foo() {
>     while(…) {
>         guard x > 0
>     }
> }
>
> if guard defaulted to return even inside a while (as was suggested), this
> might be counterintuitive.
>
> On Dec 16, 2015, at 5:06 PM, Etan Kissling via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> Also +1 on default return, -1 on default continue / break, and -1 for
> removing braces
>
> Instead of VoidLiteralConvertible, one could extend on the idea with
> something that is not specifically tailored to nil, like
>
> func foo(x: Int) -> Int = 5 {
>     guard x < 10 // Would return default 5 for x >= 10
>
>     if x > 5 {
>         return // Would return default 5
>     }
>     return x
> }
>
>
>
> Etan
>
>
> On 16 Dec 2015, at 19:39, Ian Ynda-Hummel via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> I am also +1 for implicit return, but -1 on continue/break for the reasons
> already stated.
>
> I'm -1 for removing braces for one-liners. I think maintaining braces
> around blocks helps distinguish them from expressions. For example,
>
>     guard x < 10 else return
>
> would catch me off guard (pardon the pun).
>
> I think I'm -1 on VoidLiteralConvertible, but I'm somewhat undecided. I
> think that separating the return value from the actual return point could
> lead to a lot of confusion, and would subsequently also make it easy to
> accidentally return the default value when you didn't intend to as the
> compiler wouldn't complain about a missing return value.  I don't think I
> have totally convinced myself that the latter is a non-trivial problem, but
> I thought it was worth mentioning.
>
> On Wed, Dec 16, 2015 at 11:59 AM ilya via swift-evolution <
> swift-evolution at swift.org> wrote:
>
>> Actually I thought about VoidLiteralConvertible some more and now I think
>> if we include it the only nontrivial case in the standard library case
>> should be Optional.Nonel. Empty arrays and dictionaries are different from
>> nothing, so it's best to always return them explicitly.
>>
>> Oh, and it would help with default values, e.g.
>>
>> var something:Something?
>> // where does the default value come from? VoidLiteralConvertible!
>>
>> I want all default values for String in this scope be "none":
>>
>> private extension String: VoidLiteralConvertible { ... return "None" ... }
>>
>> On Wed, Dec 16, 2015 at 10:49 ilya <ilya.nikokoshev at gmail.com> wrote:
>>
>>> +1 on default return
>>>
>>> -1 on default continue or break, this is ambiguous.
>>> Even inside switch it's not clear if guard should break or return, so
>>> let's not make people guess. .
>>>
>>> Also can we stop requiring braces for simple one-liners:
>>>
>>> guard x<10 else return 5
>>>
>>> As for default return values, we could create a VoidLiteralConvertible,
>>> so that default return automatically becomes return nil or return [] in an
>>> Optional or Array context respectively. As a bonus, it will be technically
>>> possible to override this behavior inside a specific function scope.
>>>
>>> > swift would provide a warning that the guard statement needs an else
>>> block
>>>
>>> In this specific case the compiler basically has to guess, so an error
>>> seems more appropriate.
>>>
>>> Ilya.
>>>
>>> On Wed, Dec 16, 2015 at 02:53 Vester Gottfried via swift-evolution <
>>> swift-evolution at swift.org> wrote:
>>>
>>>> I find myself writing the same else blocks for guard statements over
>>>> and over again, so it might be reasonable to think about a default
>>>> behaviour.
>>>>
>>>> In a current project I found 217 guard statements from which 183 have
>>>> repetitive else clauses
>>>>
>>>> From which:
>>>> 131 end with "else { return nil }"
>>>> 44 "else { return }"
>>>> 6 "else { continue }"
>>>> 2 "else { break }"
>>>>
>>>> My proposal would be to make the else block optional and define a
>>>> default behaviour.
>>>>
>>>> For example:
>>>>
>>>> func foo(x: Int) {
>>>> ​    ​
>>>> guard x < 10
>>>> ​    ​
>>>> ...
>>>> }
>>>>
>>>> swift would implicitly add "else { return }"
>>>>
>>>> --
>>>>
>>>> func foo(x: Int) -> Int? {
>>>> ​    ​
>>>> guard x < 10
>>>> ​    ​
>>>> ...
>>>> }
>>>>
>>>> swift would implicitly add "else { return nil }"
>>>>
>>>> --
>>>>
>>>> for i in 0..<10 {
>>>> ​    ​
>>>> guard i%2 == 0
>>>> }
>>>>
>>>> swift would implicitly add "else { continue }"
>>>>
>>>> --
>>>>
>>>> switch {
>>>> case a :
>>>> ​    ​
>>>> guard x != y
>>>> case b :
>>>> ​    ...​
>>>>
>>>> }
>>>>
>>>> swift would implicitly add "else { break }"
>>>>
>>>> --
>>>>
>>>> func foo(x: Int) -> Int {
>>>> ​    ​
>>>> guard x < 10
>>>> ​    ​
>>>> ...
>>>> }
>>>>
>>>> swift would provide a warning that the guard statement needs an else
>>>> block
>>>>
>>>> --
>>>>
>>>> Possible advantages
>>>> - Less code
>>>> ​ to write​
>>>>
>>>> - visually cleaner
>>>> -
>>>> ​ ​
>>>> In code with multiple guard statements
>>>> ​ ​
>>>> you
>>>> ​ ​
>>>> would not have to repeat the else block
>>>>
>>>>
>>>> Possible Disadvantages
>>>> - Different behaviour in different contexts (func/return, for/continue,
>>>> switch/break, …) needs to be learned and understood
>>>> - programmers might forget that guard + else {} is an option
>>>>  _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>
>>>  _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>
>  _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
>
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151216/4b4dd85a/attachment.html>


More information about the swift-evolution mailing list