Using Guard with a Non-Optional Value Assignment

Using guard with a non-optional value assignment

If you throw a case in there, it'll work. So as follows:

guard case let c = parts.count where c > 1 else { return }

Create non-optional in guard to test guarded condition

The "trick" is to use guard case with a value-binding pattern for the assignment:

func doSomething() {
guard case let newString = goGetANewString(), newString != currentString else {
return
}

currentString = newString
}

Unwrapping optionals to a pre-defined variable in the guard condition without creating a new constant

I would just test for nil and then force unwrap when I know it's not:

var someString: String? = "hello"
let nonOptionalString: String // note, you don't have to initialize this with some bogus value

guard someString != nil else { return }
nonOptionalString = someString!

Or if someString was a parameter to some method or closure, you can unwrap in the guard statement using the same variable name, simplifying life even more:

func foo(someString: String?) {
guard let someString = someString else { return }

// now I can just use local `someString`, which is not optional anymore
}

If you're desperate to unwrap and exit-if-nil in a single statement, you could theoretically write a function to unwrap if it can or throw an error if it can't:

extension Optional {
enum OptionalError: Error {
case unwrapFailed
}

func unwrap<T>() throws -> T {
if self == nil { throw OptionalError.unwrapFailed }
return self as! T
}
}

Then you can do:

do {
firstNonOptional = try firstOptional.unwrap()
secondNonOptional = try secondOptional.unwrap()
thirdNonOptional = try thirdOptional.unwrap()
} catch {
return
}

I think that's horrible overkill, but if you're desperate to distill it down to one line per unwrap, that's one way to do it.

How to use guard statement to detect nil after an assignment?

The other answers show you how to solve your issue, but doesn't really explain why this error occurs, so I thought I'd pitch in on that.


The guard let ... else statement, much like if let ..., attempts to bind the unwrapped value of an optional---generally as long as this is not nil---to a non-optional immutable of the same underlying type; using optional binding

var a: Int? = 5
if let b = a {
// b unwrapped, type inferred to non-optional type Int
print(b) // "5"
}

The above binding would fail if a had the value nil, as b, as per default (by type inference), is of type Int which cannot hold nil.

In this context, it makes no sense to explicitly declare b to be an implicitly unwrapped optional, as this will allow a successful binding even if a is nil. An equivalently non-sense block would be to explicitly declare b to be an optional, whereafter the "attempted optional binding" of optional a (Int?) to optional b (Int?) would naturally always succeed, and the if let ... block reduces to a completely redundant block-local assignment.

a = nil

if let b: Int! = a {
print(b) // "nil"
// wups, we managed to bind a to b even though a is nil ...

// note also this peculiarity
print(b.dynamicType) // Optional<Int>
let c: Int! = nil
print(c.dynamicType) // ImplicitlyUnwrappedOptional<Int>
}

if let b: Int? = a {
print(b) // nil
// wups, we managed to bind a to b even though a is nil ...
}

Note the peculiarity that no matter if we explicitly specify b to be of type Int? (optional) or type Int! (implicitly unwrapped optional), the binded immutable b passing into the if let block is, for both cases, just a regular optional (of type Int?). This explains why you need to unwrap event (event!.iconImgData) after the guard let clause, even though we declared it to be of an implicitly unwrapped type.

Hence, in your example, your guard let ... else statement will not catch cases where eventsImagesLoading.removeValueForKey(location) is nil, as the binding to event (which is of implicitly unwrapped optional type Event!) will success even for nil cases.

func foo() {
let bar : Int? = nil
guard let _: Int! = bar else {
print("this is surely nil")
return

}
print("but an implicitly unwrapped optional will fall through")
}
foo() // "but an implicitly unwrapped optional will fall through"

You should generally only use implicitly unwrapped optionals for immutables where you need delayed initialization (value nil until initialized). After initialization of an implicitly unwrapped optional, its value should never be nil (whereas in the example above, it's value is, after initialization by optional binding, just that; nil).

Also, you should generally let the compiler infer the non-optional type of the immutable to which you are trying to bind in the guard let INFER_THIS = ... else or if let INFER_THIS = ... clauses.


We could ponder over whether it should even be allowed to use optional binding to optional types (guaranteed success), but that is another discussion.

Property annotation that checks assignment to a guard value initially set to None

After a night's sleep I got the solution: splitting up the typing responsibilities from the guarding responsibilities.

  • the guard variable, self/cls._the_answer is left untyped.

  • In line 15, right under the guard condition which tells me the instance hasn't had that property computed yet, I type-hint a new variable name, answer.

Both incorrect assignments, in 21 and 24 are now flagged.

from typing import cast
class Book:
def __init__(self, title):
self.title = title

_the_answer = None

def __str__(self):
return "%s => %s" % (self.title, self.the_answer)

@property
def the_answer(self)->int:
"""always should be an int. Not an Optional int"""
if self._the_answer is None:
answer : int #line 15: this is where the typing happens
if "Guide" in self.title:
#this is OK ✅
answer = 42
elif "Woolf" in self.title:
#this is wrong ❌
answer = "?, I haven't read it" # line 21
else:
#mypy should also flag this ❌
answer = None #line 24
self._the_answer = answer
return cast(int, self._the_answer) #line 26

print(Book("Hitchhiker's Guide"))
print(Book("Who's afraid of Virginia Woolf?"))
print(Book("War and Peace"))

Same actual run output as before.

mypy output:

Now, both problem lines are flagged ;-)

test_prop4.py:21: error: Incompatible types in assignment (expression has type "str", variable has type "int")
test_prop4.py:24: error: Incompatible types in assignment (expression has type "None", variable has type "int")

What about the cast in line 26? What if nothing assigns answer in the if statements? Without the cast, I'd probably be getting a warning. Could I have assigned a default value as in answer : int = 0 in line 15?

I could, but unless there really is a good application-level default, I'd rather have things blow up right away at execution (UnboundLocalError on answer) rather than making mypy happy but having to chase down some weird runtime value.

That last bit is totally dependent on what your application is expecting, a default value may be the better choice.

Swift: guard let vs if let

if let and guard let serve similar, but distinct purposes.

The "else" case of guard must exit the current scope. Generally that means it must call return or abort the program. guard is used to provide early return without requiring nesting of the rest of the function.

if let nests its scope, and does not require anything special of it. It can return or not.

In general, if the if-let block was going to be the rest of the function, or its else clause would have a return or abort in it, then you should be using guard instead. This often means (at least in my experience), when in doubt, guard is usually the better answer. But there are plenty of situations where if let still is appropriate.

Swift : If variable a is non-optional then why variable b is an optional?

Variable b is an optional because variable a 'might' return nil and in such case b will also be nil.

Edit:
You have assigned an optional variable to another variable which you have not defined a specific type for. Xcode is saving you by creating the variable b as an optional. Consider this example:

var a: Int! = 6
a = nil
let b: Int = a
print(b)

Similar to yours, variable a here is an optional of type Int and b is a nonoptional of type Int too. Here I specifically define b to be a non optional integer unlike your b variable. Now, if i try to print variable who is assigned value of a which was at that point nil. This is dangerous and simply results in a fatal error at the assignment statement. The crash is simply understood because the compiler finds a nil value in a the optional type and tries to assign it to a non-optional.

Only optionals can hold nil value therefore when you assigned an optional(nillable) to another variable b, it is automatically treated as an optional because the value on which it relies is nillable and hence variable b is also nillable.

Why can you assign non-optional values to optional types in Swift?

This is part of the syntactic sugar behind optionals. Assigning a non-optional value is how you wrap it in the optional type.

Since an optional indicates the presence or absence of a value, you shouldn't have to do anything special to indicate the presence of a value other than provide one. For example, in a function:

func gimmeSomethingMaybe() -> String? {
if arc4random_uniform(10) > 7 {
return "something"
} else {
return nil
}
}

Imagine if every time you wanted to return a real value from a function that's capable of returning nil, you had to write return Optional(value). That'd get old pretty fast, right? Optionals are an important feature of the language — even though they're actually implemented by the standard library, the syntactic sugar / automatic wrapping is there to keep it from being tedious to use them.


Edit: just to go a bit further into this... the sugar also helps to enforce the notion that a real value should not be optional. For example:

let one = 1
one? // error (in Swift 1.2, allowed but meaningless in Swift 1.1)
"two"? // error (ditto)

You can create an optional wrapping a real value with the Optional(one) initializer, but that has little semantic meaning on its own, so you almost never need to.

Optionals should come into play when there's "mystery" as to whether a value is present or absent — that is, when whether one part of a program receives a value (or no value) depends on state unknown to that part of the program. If you know you have a real value, there's no mystery... instead, you let the unknown come into play at the boundary between the code that knows the value and the code that doesn't know — that is, the function/method/property definition that hands that value off to somewhere.



Related Topics



Leave a reply



Submit