Why doesn't 'guard let ...' allow non-optionals?

45 views
Skip to first unread message

Jens Alfke

unread,
Jul 14, 2015, 6:18:14 PM7/14/15
to swift-l...@googlegroups.com
It seems inconsistent that I can use a ‘guard’ statement to bind an optional value, but not to bind anything else. For example, if foo.color is an optional I can use
guard let color = foo.color else { return }  // works
but if foo.count is an integer I can’t use
guard let count = foo.count where foo.count > 0 else { return }  // syntax error
This would actually work as long as foo.count were an optional integer, which seems like a weird requirement in this case.

I’m finding this is getting in the way of my using ‘guard let...’ as a uniform way of expressing preconditions in methods, because of course not all preconditions involve optionals.

I know I can do
let count = foo.count
guard foo.count > 0 else { return }
but it would feel more consistent (and compact!) to be able to use ‘guard let’ in all cases.

—Jens

Adam Sharp

unread,
Jul 14, 2015, 7:10:44 PM7/14/15
to swift-l...@googlegroups.com
I agree, it seems like a frustrating limitation. However I think your example can work if you just throw a "case" in front of your "let":

guard case let count = foo.count where foo.count > 0 else { return }

–Adam

--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to swift-languag...@googlegroups.com.
To post to this group, send email to swift-l...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/91453610-7ED2-4479-9814-B26524692A9B%40mooseyard.com.
For more options, visit https://groups.google.com/d/optout.

Marco S Hyman

unread,
Jul 14, 2015, 7:55:49 PM7/14/15
to Adam Sharp, swift-l...@googlegroups.com

> On Jul 14, 2015, at 4:10 PM, Adam Sharp <ads...@me.com> wrote:
>
> I agree, it seems like a frustrating limitation. However I think your example can work if you just throw a "case" in front of your "let":
>
> guard case let count = foo.count where foo.count > 0 else { return }

That brings up another “case” that confuses me.

let bar: Int? = 42

if let foo = bar {
print(foo)
}

if case let foo? = bar {
print(foo)
}

Both print “42\n”. I haven’t yet wrapped my head around why the case version
requires foo? instead of foo unless I want foo to be optional ???

Marc

Jens Alfke

unread,
Jul 14, 2015, 9:21:15 PM7/14/15
to Adam Sharp, swift-l...@googlegroups.com
On Jul 14, 2015, at 4:10 PM, Adam Sharp <ads...@me.com> wrote:

I agree, it seems like a frustrating limitation. However I think your example can work if you just throw a "case" in front of your "let":

guard case let count = foo.count where foo.count > 0 else { return }

Ah, thanks! I’m still coming to grips with the way 'case' has been detached from its longtime home in ‘switch’ statements and can now be sprinkled into other contexts like this. O_o

—Jens

Adam Sharp

unread,
Jul 14, 2015, 9:38:25 PM7/14/15
to swift-l...@googlegroups.com
Yeah, to be honest it feels like the number of keywords and the rules for their use is getting close to becoming unwieldy. In this case (heh) it almost begins to feel a little arbitrary, or at least unintuitive.

–Adam

Jeremy Pereira

unread,
Jul 15, 2015, 9:33:40 AM7/15/15
to Jens Alfke, swift-l...@googlegroups.com

> On 14 Jul 2015, at 23:18, Jens Alfke <je...@mooseyard.com> wrote:
>
> It seems inconsistent that I can use a ‘guard’ statement to bind an optional value, but not to bind anything else. For example, if foo.color is an optional I can use
> guard let color = foo.color else { return } // works
> but if foo.count is an integer I can’t use
> guard let count = foo.count where foo.count > 0 else { return } // syntax error

Why? The former case unwraps an optional, the latter case does nothing that guard foo.count > 0 doesn't do.

> This would actually work as long as foo.count were an optional integer, which seems like a weird requirement in this case.
>
> I’m finding this is getting in the way of my using ‘guard let...’ as a uniform way of expressing preconditions in methods,
> because of course not all preconditions involve optionals.
>
> I know I can do
> let count = foo.count
> guard foo.count > 0 else { return }
> but it would feel more consistent (and compact!) to be able to use ‘guard let’ in all cases.

IF you allow

guard let something = somethingThatIsNotAnOptional where blah

you are also into

if let something = somethingThatIsNotAnOptional where blah

and

while let something = somethingThatIsNotAnOptional where blah

which kind of obfuscates the meaning a bit by putting the only thing that matters (the conditional) at the end.

if blah
{
let something = somethingThatIsNotAnOptional
...
}

is a bit easier to understand IMO

Leonardo Faoro

unread,
Jul 16, 2015, 8:10:47 AM7/16/15
to swift-l...@googlegroups.com
Code should first of all be readable, allowing guard let for everything would confuse other programmers reading the code which expect an Optional out of this syntax.

Jens Alfke

unread,
Jul 16, 2015, 12:24:38 PM7/16/15
to Leonardo Faoro, swift-l...@googlegroups.com

On Jul 16, 2015, at 5:10 AM, Leonardo Faoro <lfa...@me.com> wrote:

Code should first of all be readable, allowing guard let for everything would confuse other programmers reading the code which expect an Optional out of this syntax.

I see the purpose of ‘guard’ as being to enforce a precondition. When you see a ‘guard’ statement you know that, unless the following condition is met, the flow of control cannot continue. That’s very valuable for readability and maintainability.

But you’re correct that the syntax for a non-optional binding in a guard doesn’t start with ‘guard let’. I’m happy with that; I just want the ability to do it.

—Jens
Reply all
Reply to author
Forward
0 new messages