Moving toward deprecating force unwrap from Swift?

core team feedback

Hi John,

Thanks for the thread wrap up. The core team discussed this thread and, as you surmise, deprecating the force unwrap postfix operator is out of the question, though not just for source stability reasons. We believe force-unwrap and force-try are valuable tools and would not entertain a proposal to deprecate or remove them. We think adding some wording to this effect to the Commonly Proposed document probably makes sense.

Participants are welcome to continue to discuss the stylistic merits of avoiding force unwraps, but that should be done in the Using Swift section of the forum rather than the Evolution section.

Cheers,
Ben

17 Likes

Hi Ben, thanks for the feedback. I'm still happy I asked the question. I've had a difficult relationship with force-unwrap over the years from the very beginning. Could we not have had an opt-in warning as a compromise? The PR was prepared and is of very modest scope. Go on, Go on Go on Go on.

1 Like

What's the motivation for an opt-in warning as opposed to the status quo, where users who wish to discourage/prohibit force unwrapping are free to use a linter to produce a warning/error?

Well that's all very well but my last encounter with a linter was on a large Open Source project that had it preconfigured into the build. I had to a) install it and b) ended up filing a PR on the linter's project as it was crashing (due to a force unwrap IIRC). I personally don't feel the compiler should shy away from linting options just on principle. Internally the compiler has assembled the AST on which such analysis can really be performed definitively to the extent that the PR I have in mind is only 22 lines, I don't think it can be rejected on grounds of risk.

That has been the longstanding principle articulated by the core team through multiple proposals.

3 Likes

@xwu, please give the core team time to speak for themselves if they want to. I didn't follow it but I thought the previous conversations about adding options were about not wanting to open the floodgates to options to turn warnings off as you can with clang for bad imports from Objective-C though there may be other instances (and in general suppressing warnings is a pretty bad idea.) In this case it is an option to opt-into a warning which for me stands out as something people might be advised to use.

Speaking personally, not on the behalf of the core team:

We've generally aimed to reduce number of compiler flags in general. This makes build system / package management simpler, and reduces the fragmentation of the Swift community into subdialects. This is an issue that (for example) C++ has had where there are large groups that use -fno-exceptions and that code doesn't work optimally with camps that use exceptions.

I think that what you're asking for here (played forward) is a little bit different though - you're suggesting that we build linting tools into the compiler and make it possible to enable them as part of the flow.

I'm (speaking personally) not necessarily opposed to that - I think that a well considered framework for this and infra to support it could be useful. However, I would recommend starting from the framework (incl the overall UX, e.g. should these be a new kind of issue?) rather than adding a few one-off warnings.

-Chris

9 Likes

Agreed. TypeScript supports some lint checks in the TSConfig file. It would be great if Swift understood a SwiftConfig file that could carry similar configs. https://www.typescriptlang.org/tsconfig

I have a suggestion to compile the sentiments expressed in this thread and, for instance, in the !! pitch and add them to the commonly rejected list.

I frequently witness similar discussions on other social platforms, and, given the number of implementations similar to this one, there might be a fairly large demographic that considers force-unwrapping an unwanted feature and a language flaw. Having counterexamples and a rationale can not only prevent redundant pitches, but also provide some educational value.

1 Like

After reading this forum for several weeks, I am fully in opposition to removing forced unwrap from the language as it is spelled and enabled today. It is clear that even in my own usage of forced unwrap, it is used in specific cases that make my life easier and cause zero harm. For others, the feature seems used for optimization (I don't actually know if forced unwrap is quicker than if let, but it seems reasonable to assume so. In my case, I use it for three reasons:

  1. When debugging <--- ESPECIALLY. There have been bugs in Swift that don't report something is nil, never break on the correct line, crash and I have NO idea why. Forced unwrap solved the problem SO many times and forced the app to crash correctly.
  2. When I have extremely large data structures that are guaranteed to have non nil optionals after a particular flag is set. The structures and classes I design are often large and arrive at such a condition after loading lots of external resources. I have ZERO desire to write an *if let when that condition is set.
  3. When I have a function that needs to initialize a variable (which is optional) and then I need to return that same object. e.g
class NotEverythingIsNonNilUntilAllThingsAreLoaded {
    var thing: SomeThing?
    func someFunctionThatIsCalledWhenSomethingIsNeeded() -> SomeThing {
        self.thing = SomeThing()
        self.thing!.cat = 100 //it was just initalized, I don't need to check if self.thing not nil
        return self.thing! //I'm definitely not wrapping this in an if let to find out what I already know.
    }
}

This is similar to what might be written in a lazy like getter minus the check to see if it was already initialized.

You're not going to make me believe I should have used an if let to return what I just created or that I need to create another variable just to return that variable with out have to use forced unwrap.

As for people who are very excited to add messages everywhere. This example does NOT require some sort of assertion with an even more detailed explanation of why it crashed. If it crashed, it wasn't the forced unwrap that caused it, it was some fault in the OS or Runtime.

Can you imagine how many programmers are going to just put "Something happened! Pretty impossible but it did, sorry your app crashed bro." or leave the messages as "" <-- those are blank quotes.

Furthermore, the default in Swift is to not use optionals at all. Most properties of a class or structure are asked to be initialized by default-- at least that is what the language almost forces us into--. So allowing the continued existence of the forced unwrap postfix operator spelled '!' is not anything to concern about.

We've already reached the edge of where the Nanny-programming language needs to hold power.

I understand what the intent was in this proposal, but it ignores the useful cases which make it handy and hardly dangerous. It's also overkill on safety.

Swift can not be perfect, it's written in C++ for God's sake.

No need for if let here

class NotEverythingIsNonNilUntilAllThingsAreLoaded {
    var thing: SomeThing?
    func someFunctionThatIsCalledWhenSomethingIsNeeded() -> SomeThing {
        let thing = SomeThing()
        thing.cat = 100 // no need for force unwrap
        self.thing = thing
        return thing
    }
}

Not disagreeing with the other things you wrote, just this one example seems like it can be solved.

Thank you!

2 Likes

There are times that a property has the force unwrap because it can’t be assigned a default or given a value at init but the class cannot function without it. I don’t think it’s a sign of lazy programming to do the force at the property declaration and not unwrap it 20 times in the body of the class.

I'm closing this thread, to stop the ongoing discussion of a topic the core team's already ruled on, since newcomers to the thread won't see the buried core team guidance.

To summarize:

  • The core team won't entertain any proposals to deprecate or remove force-unwraps (or force tries). That includes a mode enabled via a compiler flag.
  • This is for more than just source compatibility reasons: we believe they are a legitimately useful part of the language.
  • Style discussions about when to use or avoid them is a fine discussion topic but should be done over on the "Using Swift" section of the forums
  • There is a potential topic of whether the Swift compiler should gain more general "linting" capabilities, which could enable an effect similar to a targeted "warn on force-unwrap" capability. The core team doesn't have any official position on whether this is a good or bad idea yet if anyone wanted to explore it. Discussion of this could be done on a spin-off topic (probably in the discussion section rather than pitches).
31 Likes