Optional Binding to an Immutable Explicitly Declared to Be of Type 'Implicitlyunwrappedoptional<T>' Yields an Immutable of Type 'Optional<T>'

Why create Implicitly Unwrapped Optionals, since that implies you know there's a value?

Consider the case of an object that may have nil properties while it's being constructed and configured, but is immutable and non-nil afterwards (NSImage is often treated this way, though in its case it's still useful to mutate sometimes). Implicitly unwrapped optionals would clean up its code a good deal, with relatively low loss of safety (as long as the one guarantee held, it would be safe).

(Edit) To be clear though: regular optionals are nearly always preferable.

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.

Initialize instance variables inside instance function

This occurs because

var someVar: Footer!

does not define a variable of type Footer but a variable of type Optional<Footer> that is implicitly unwrapped. The code:

var someFooter: Footer! 

bind(footer: &someFooter)

is logically equivalent to

var someFooter: Footer? 

guard let tempFooter = someFooter? else { fatalError() }
bind(footer: &tempFooter)

As you can see, tempFooter is a let, so it can't be passed as an inout variable and even if it could, the result would be thrown away.

You can fix this in one of three ways:

  • make the parameter to bind an optional, e.g. func bind(footer: inout Footer?) or use Martin's syntax to make it implicitly optional.

  • Force the unwrap yourself:

    var unwrapped: Footer = someFooter
    bind(footer: unwrapped)
    someFooter = unwrapped
  • redesign the API. It seems the first thing you do in the bind function is overwrite the old footer with a newly initialised footer. So don't use an inout parameter, return the value you want i.e.

    func bind() -> Footer
    {
    var theFooter = Footer(...) { ... }
    // do stuff

    return theFooter
    }

    someFooter = bind()

I think the last option is the best in this case.

Swift 'if let' statement equivalent in Kotlin

You can use the let-function like this:

val a = b?.let {
// If b is not null.
} ?: run {
// If b is null.
}

Note that you need to call the run function only if you need a block of code. You can remove the run-block if you only have a oneliner after the elvis-operator (?:).

Be aware that the run block will be evaluated either if b is null, or if the let-block evaluates to null.

Because of this, you usually want just an if expression.

val a = if (b == null) {
// ...
} else {
// ...
}

In this case, the else-block will only be evaluated if b is not null.



Related Topics



Leave a reply



Submit