Moving toward deprecating force unwrap from Swift?

Additionally, there's nothing about not having force unwraps that prevents your app from crashing.

The syntax is just shorthand for guard else throw fatal.

I strongly disagree. Force unwrapping is a powerful tool and any tool could be used for good and for bad. Off-by-one errors are very common, but we aren't banning arrays, right?

4 Likes

Not exactly. fatalError lets you set a custom message (including values that may be useful for debugging) while ! just shows the generic “tried to unwrap nil” error. In tools like Crashlytics, this makes fatalError a lot more useful.

2 Likes

Swift is not used just for applications. Force unwrapping is very useful in scripts.
I wouldn’t want to have to write guard let everywhere in a quick script.

12 Likes

True, and likewise such shortcuts are desirable when doing things like Advent of Code or quick prototypes, where speed of writing code is a factor.

3 Likes

Not really, since the message is stripped from the crash report. In the end the look pretty much the same.

Not in my experience...

1 Like

That looks like some sort of custom logging, not the crash log itself. Or perhaps Crashlytics can now intercept those messages separately. In any case, they’re stripped from the actual crash log.

I'm not sure, but I think this is [SR-905] precondition failure should show message in crash report · Issue #43517 · apple/swift · GitHub (fatalError emits strings, but not precondition failures)

Hard disagree. Force unwrap is very useful when used appropriately and using guard let to unwrap is tedious and unnecessary.

8 Likes

Different compulsions happen to work at cross purposes. I enjoy having good test coverage, and when used appropriately a force unwrap avoids untestable code. I think untestable code is much worse than forced unwrapping.

5 Likes

to throw someBadURLError, one have to create a type which apply Error protocol or use objC NSError so this code in not complete and have to have few lines more.

This makes Swift REPL less usable if there is no force unwrap.

you example show us an important issue about Swift compiler that is not smart enough to know that its not nil, one of Kotlin amazing feature .

guard error == nil else {
        print(error!) // No real access to error, but we know it exists
        return
    }

by looking at Kotlin compiler , it is smart enough to detect that value is not null

fun main() {
        var value: Int? = 5 
    if (value != null) {
        print(value)
    }
}
1 Like

by looking at Kotlin compiler , it is smart enough to detect that value is not null

I'm quite glad we don't go this way in Swift as the complexity of such checking would be enormous. Checking local, strong variables can be easy, but consider the same construct used f.e. with a weak variable, property, inout, etc. (not even considering chaining – the compiler needs to be consistent in so many cases) where the variable behind some symbol can be valid at the condition point and become nil inside the block due to mutation from another thread.

We don't really want to trade safety and unnecessary compiler complexity just to drop a single “ugly” character; even using value! in such cases can be considered unsafe for these specific reasons – that's we we need to use force unwrap as a sign of unsafe point in the first place. Proper strongify/unwrapping is the only safe way to go.

To force wrap the discussion :smiley: SwiftLint really does a good job here for everyone who has a desire to wipe force unwrapping from the codebase, and the benefits of this construct along with the fact it's an opt-in, conscious tool, make it a welcomed thing to have available when needed.

4 Likes

There are already a lot of discussions for that: Implicit Casts for Verified Type Information.

4 Likes

Interesting discussion

In our codebase we ban force unwrapping using SwiftLint which I'm quite happy about, our crash rate is extremely low and it forces us to think about edge cases. That said using force unwrap is required in some places, like when we hardcode URLs in our config files, and there we can disable the swift lint rule on that line.

Also not every piece of Swift code needs to be production ready. Scripting in Swift is a thing and being able to force unwrap to exit early if something is unexpected is really useful, and allows writing scripts quickly and concisely.

If the Swift compiler allowed disabling warnings then deprecating force unwrap would be acceptable, but unfortunately that seems like it will never happen. Adding warnings to people's codebases without the ability to silence them really isn't useful as it adds noise that will hide other warnings in the codebase.

For example recently a warning was added for "Immutable property will not be decoded because it is declared with an initial value which cannot be overwritten" we knew this and the behaviour that happens is expected but now our project has a 100 warnings getting in the way of real ones because there's no way to say actually this is the behaviour we want (without changing the perfectly valid code)

This should be left up to linters until we can disable compiler warnings.

2 Likes

What I am missing is a safe unwrap operator for such cases:

func f(value: Int?) {
    if value != nil {
        print(value¡) // ok, safe to unwrap
    }
    print(value¡) // compile time error, unsafe to unwrap
}

I took ¡ for this example, the best would have been to choose ! for safe and !! for unsafe unwrap. But that ship has sailed unfortunately...

What I am missing is a safe unwrap operator for such cases:

That's what the if let … expression is for – otherwise you could only run into scenario I've just described. There's no easy nonnull guarantee with simple if sth != nil condition.

1 Like

It cannot be emphasized enough that ! is the safe unwrapping operator, because trapping is safe. The spelling for unsafe unwrapping is unsafelyUnwrapped.

10 Likes