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

Etan Kissling kissling at oberon.ch
Wed Dec 16 16:20:09 CST 2015


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 <mailto: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 <mailto: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 <mailto: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 <mailto: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 <mailto: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 <mailto:swift-evolution at swift.org>
>>> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>  _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>  _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
>> 
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org <mailto: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/cd8e0722/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 801 bytes
Desc: Message signed with OpenPGP using GPGMail
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151216/cd8e0722/attachment.sig>


More information about the swift-evolution mailing list