Proposal: Add implicit/default else-behaviour for the guard statement


(Vester Gottfried) #1

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


Inferred return for guard statement
(David Waite) #2

<snip>

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 }”

That makes sense

--

func foo(x: Int) -> Int? {
​ ​guard x < 10
​ ​…
}

swift would implicitly add "else { return nil }”

You would need to decide how this plays into the type system
- is Optional a special case
- or, will it work with anything NilLiteralConvertible (Optional, ImplicitlyUnwrappedOptional, Pointer types, Selectors)

I thought of using the no-argument initializer, but that creates too much default behavior (empty arrays, zero doubles, etc).

Plus, it is inconsistent with variable declarations, which require explicit initialization before use.

--

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 }"

-1 . Flow control functions need to be explicit, else I risk having (and assuming) the wrong behavior when I copy and paste code from one context to another.

Plus, why would I expect a guard in a for loop to break or continue as a default behavior? I personally know I would constantly think this guard as ‘does what I mean’, while in the debugger it seems to be doing exactly the opposite of what I assumed, every time, regardless of my assumption :wink:

func foo(x: Int) -> Int {
​ ​guard x < 10
​ ​...
}

swift would provide a warning that the guard statement needs an else block

Iff your proposal was to call the no-argument initializer, this would return 0. For the other options this would need to return an error, not a warning.

-DW

···

On Dec 15, 2015, at 4:53 PM, Vester Gottfried via swift-evolution <swift-evolution@swift.org> wrote:


(ilya) #3

+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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Pierre Monod-Broca) #4

Looking at the numbers it would make sense mostly to return from a function. And I agree with David that control flow in loops and switches should be explicit.

So maybe a function could declare a default behavior for all its `guard`

Pierre

···

Le 16 déc. 2015 à 01:42, David Waite via swift-evolution <swift-evolution@swift.org> a écrit :

On Dec 15, 2015, at 4:53 PM, Vester Gottfried via swift-evolution <swift-evolution@swift.org> wrote:

<snip>

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 }”

That makes sense

--

func foo(x: Int) -> Int? {
​ ​guard x < 10
​ ​…
}

swift would implicitly add "else { return nil }”

You would need to decide how this plays into the type system
- is Optional a special case
- or, will it work with anything NilLiteralConvertible (Optional, ImplicitlyUnwrappedOptional, Pointer types, Selectors)

I thought of using the no-argument initializer, but that creates too much default behavior (empty arrays, zero doubles, etc).

Plus, it is inconsistent with variable declarations, which require explicit initialization before use.

--

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 }"

-1 . Flow control functions need to be explicit, else I risk having (and assuming) the wrong behavior when I copy and paste code from one context to another.

Plus, why would I expect a guard in a for loop to break or continue as a default behavior? I personally know I would constantly think this guard as ‘does what I mean’, while in the debugger it seems to be doing exactly the opposite of what I assumed, every time, regardless of my assumption :wink:

func foo(x: Int) -> Int {
​ ​guard x < 10
​ ​...
}

swift would provide a warning that the guard statement needs an else block

Iff your proposal was to call the no-argument initializer, this would return 0. For the other options this would need to return an error, not a warning.

-DW

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(ilya) #5

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@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@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@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Ian Ynda-Hummel) #6

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@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@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@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@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


(Etan Kissling) #7

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

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.

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" ... }

+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 16 Dec 2015, at 19:39, Ian Ynda-Hummel via swift-evolution <swift-evolution@swift.org<mailto:swift-evolution@swift.org>> wrote:
On Wed, Dec 16, 2015 at 11:59 AM ilya via swift-evolution <swift-evolution@swift.org<mailto:swift-evolution@swift.org>> wrote:
On Wed, Dec 16, 2015 at 10:49 ilya <ilya.nikokoshev@gmail.com<mailto:ilya.nikokoshev@gmail.com>> wrote:

On Wed, Dec 16, 2015 at 02:53 Vester Gottfried via swift-evolution <swift-evolution@swift.org<mailto:swift-evolution@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@swift.org<mailto:swift-evolution@swift.org>
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<mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution


(Vinicius Vendramini) #8

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@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@swift.org <mailto:swift-evolution@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@swift.org <mailto:swift-evolution@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@gmail.com <mailto:ilya.nikokoshev@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@swift.org <mailto:swift-evolution@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@swift.org <mailto:swift-evolution@swift.org>
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 <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


(Etan Kissling) #9

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@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@swift.org <mailto:swift-evolution@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@swift.org <mailto:swift-evolution@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@swift.org <mailto:swift-evolution@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@gmail.com <mailto:ilya.nikokoshev@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@swift.org <mailto:swift-evolution@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@swift.org <mailto:swift-evolution@swift.org>
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 <mailto:swift-evolution@swift.org>
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


(Vester Gottfried) #10

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@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@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@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@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@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@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@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@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

_______________________________________________
swift-evolution mailing list
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

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


#11

I'm opposed. I don't think `else { return }` is enough of a mouthful to add
a default behavior that must be learned and reasoned with.

Stephen

···

On Wed, Dec 16, 2015 at 5:36 PM, Vester Gottfried via swift-evolution < swift-evolution@swift.org> wrote:

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@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@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@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@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@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@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@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@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

_______________________________________________
swift-evolution mailing list
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

_______________________________________________
swift-evolution mailing list
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


(Radek Pietruszewski) #12

I’m also against, for two reasons:

- looking at my code, `return` and `return nil` are most common, but not super-overwhelmingly so. I’m all for common-sense default behavior, but here, I’m just not convinced it’s worth it. Likewise, I hate noise in code, but I’m not bothered by explicit `else` blocks at all.
- guard is already confusing enough until you truly, fully get it. Having an `else` block makes it far more clearer that it’s a (specialized) branching operation. Having something implicitly return from my method sounds almost scary.

— Radek

···

On 17 Dec 2015, at 00:26, Stephen Celis via swift-evolution <swift-evolution@swift.org> wrote:

I'm opposed. I don't think `else { return }` is enough of a mouthful to add a default behavior that must be learned and reasoned with.

Stephen

On Wed, Dec 16, 2015 at 5:36 PM, Vester Gottfried via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
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@swift.org <mailto:swift-evolution@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@gmail.com <mailto:vinivendra@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@swift.org <mailto:swift-evolution@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@swift.org <mailto:swift-evolution@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@swift.org <mailto:swift-evolution@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@gmail.com <mailto:ilya.nikokoshev@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@swift.org <mailto:swift-evolution@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@swift.org <mailto:swift-evolution@swift.org>
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 <mailto:swift-evolution@swift.org>
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 <mailto:swift-evolution@swift.org>
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


(Erica Sadun) #13

Count me in as a "no". Despite the redundancy, actually spelling out how the else clause leaves scope is valuable to reading the code.

-- E

···

On Dec 16, 2015, at 4:40 PM, Radosław Pietruszewski via swift-evolution <swift-evolution@swift.org> wrote:

I’m also against, for two reasons:

- looking at my code, `return` and `return nil` are most common, but not super-overwhelmingly so. I’m all for common-sense default behavior, but here, I’m just not convinced it’s worth it. Likewise, I hate noise in code, but I’m not bothered by explicit `else` blocks at all.
- guard is already confusing enough until you truly, fully get it. Having an `else` block makes it far more clearer that it’s a (specialized) branching operation. Having something implicitly return from my method sounds almost scary.

— Radek

On 17 Dec 2015, at 00:26, Stephen Celis via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I'm opposed. I don't think `else { return }` is enough of a mouthful to add a default behavior that must be learned and reasoned with.

Stephen

On Wed, Dec 16, 2015 at 5:36 PM, Vester Gottfried via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
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@swift.org <mailto:swift-evolution@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@gmail.com <mailto:vinivendra@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@swift.org <mailto:swift-evolution@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@swift.org <mailto:swift-evolution@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@swift.org <mailto:swift-evolution@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@gmail.com <mailto:ilya.nikokoshev@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@swift.org <mailto:swift-evolution@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@swift.org <mailto:swift-evolution@swift.org>
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 <mailto:swift-evolution@swift.org>
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 <mailto:swift-evolution@swift.org>
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 <mailto:swift-evolution@swift.org>
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


(Lily Ballard) #14

Agreed. Count me as a "no" as well. `else { return }` is not problematic
enough to justify the penalty to reading comprehension.

-Kevin Ballard

···

On Wed, Dec 16, 2015, at 04:30 PM, Erica Sadun via swift-evolution wrote:

Count me in as a "no". Despite the redundancy, actually spelling out
how the else clause leaves scope is valuable to reading the code.


(Andrey Tarantsov) #15

I'm conflicted.

Pros:

1) Neat. :slight_smile:

2) Um, less typing? But Xcode has snippets, you know.

3) Less visual noise? Perhaps someone considers that visual noise, but to me { return nil } is an essential part of the flow and actually helps to understand it.

4) I would love a “guard!” variant that crashes instead of returning.

Cons:

1) Can no longer find all returns by just looking for 'return'.

2) Reads more like an assertion than like a return.

I believe there are no good arguments one way or another, so we have to fall back on the taste of the core team.

A.

···

On Dec 17, 2015, at 2:35 PM, Kevin Ballard via swift-evolution <swift-evolution@swift.org> wrote:

On Wed, Dec 16, 2015, at 04:30 PM, Erica Sadun via swift-evolution wrote:

Count me in as a "no". Despite the redundancy, actually spelling out how the else clause leaves scope is valuable to reading the code.

Agreed. Count me as a "no" as well. `else { return }` is not problematic enough to justify the penalty to reading comprehension.

-Kevin Ballard

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


#16

Isn't this essentially

    let x = optionalX!

:slight_smile:

Stephen

···

On Dec 17, 2015, at 6:01 AM, Gwendal Roué via swift-evolution <swift-evolution@swift.org> wrote:

Yet I have to admit that assert and precondition can not replace guards like the following, which define a variable:

  guard let x = optionalX else {
      fatalError("Missing x")
  }
  // use x


#17

Isn’t it the role of assert and precondition?

Yet I have to admit that assert and precondition can not replace guards like the following, which define a variable:

  guard let x = optionalX else {
      fatalError("Missing x")
  }
  // use x

Gwendal Roué

···

Le 17 déc. 2015 à 11:58, Andrey Tarantsov via swift-evolution <swift-evolution@swift.org> a écrit :

4) I would love a “guard!” variant that crashes instead of returning.


#18

Yes it is :slight_smile: Happy to see you there :slight_smile:

Gwendal

···

Le 17 déc. 2015 à 14:06, Stephen Celis <stephen.celis@gmail.com> a écrit :

On Dec 17, 2015, at 6:01 AM, Gwendal Roué via swift-evolution <swift-evolution@swift.org> wrote:

Yet I have to admit that assert and precondition can not replace guards like the following, which define a variable:

  guard let x = optionalX else {
      fatalError("Missing x")
  }
  // use x

Isn't this essentially

   let x = optionalX!

:slight_smile:

Stephen


(Andrey Tarantsov) #19

4) I would love a “guard!” variant that crashes instead of returning.

Isn’t it the role of assert and precondition?

Well, there's another thread talking about an alternative name for assert. guard! could be a good one. And, yes, "guard! let" isn't currently possible with assert.

More importantly, sometimes I change my mind about whether something is a valid failure or should be a crash, and a one-character difference would be appreciated. (Granted, that doesn't happen often, just sometimes.)

A.


(Andrew Bennett) #20

I'm a +1 on the return defaults with void/optional.
Within a switch I'm on the fence, it seems reasonable to break, but you may
want to return.
Within a loop I'm against it, I think I think that continue makes the most
sense (forEach will exhibit the same behaviour), but you may want break or
return.

···

On Thu, Dec 17, 2015 at 10:01 PM, Gwendal Roué <swift-evolution@swift.org> wrote:

> Le 17 déc. 2015 à 11:58, Andrey Tarantsov via swift-evolution < > swift-evolution@swift.org> a écrit :
>
> 4) I would love a “guard!” variant that crashes instead of returning.

Isn’t it the role of assert and precondition?

Yet I have to admit that assert and precondition can not replace guards
like the following, which define a variable:

        guard let x = optionalX else {
            fatalError("Missing x")
        }
        // use x

Gwendal Roué

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution