Force Unwrap a return?

I am new to Swift and as I am still learning the optionals and I was messing around trying to force unwrap.

I thought of a way and when I asked a dev he said it is not possible:

func getWeatherStatus (status: weatherType ) -> String! {
    switch status{
    case .cloud:
        return "It's gonna rain"
    case .sunny:
        return "It's hot"
    case .wind(let speed) where speed < 10:
        return "Not that windy"
    case .wind, .snowy:
        return nil
    }

}

let weatherStatus = getWeatherStatus(status: .cloud)
print(weatherStatus)


It is only possible to use ? and not ! to force unwrap so when I make an object of it then it is already unwrapped.. I wanted to know why is it not possible or can it be implemented in the future if I am sure enough that the func will not return nil it can be force unwrapped instead of having to use as! to not get optional result

If your intent is to crash in the .wind or .snowy conditions you can replace return nil with fatalError()—the compiler knows this function will end execution of the program and so won’t require a return along that branch of the function.

2 Likes

No no my intent is if I didn't have that nil and I am positive that it will not return nil why can't I just do this:

func getWeatherStatus (status: weatherType ) -> String! {

and create the object and print it

let weatherStatus = getWeatherStatus(status: .cloud)
print(weatherStatus)

instead of doing that:

func getWeatherStatus (status: weatherType ) -> String? {

then having to force unwrap here:

let weatherStatus = getWeatherStatus(status: .cloud) as! String
print(weatherStatus)

I’m not sure I understand. If you don’t have that nil branch then the function can just return the type String and you don’t need to deal with optionals at all.

2 Likes

That's true but I was wondering since it is already possible to return optional why is it not possible to return that optional force unwrapped instead of having to unwrap it all over when I create the object.

I may not entirely understand your question/pitch, but since you're learning about optionals, I can give you some advice about optionals related to your example.

Since your function can return nil, it is recommended that it return an optional - String?. Then, anybody who calls that function needs to handle the nil value, in whichever way makes sense for them. If they are sure, for whatever reason, that the result won't be nil, they can decide to use ! to force-unwrap the optional (for example, because it is documented that .cloudy never returns nil), but the important point is that it's the caller's decision about how they handle nil values.

If the function itself promises to never return nil, it should not be returning an optional.

5 Likes

Yes exactly, it is possible to return -> String? but not possible to return -> String!, why? what if I wanted it instead of returning optional and having to unwrap it. why can't I return it already unwrapped by from the start?

What exactly is the behavior you expect from “return[ing] that optional force unwrapped”? I’m assuming we’re in a case like the one from your post where we actually have a branch in the code that returns nil but for some reason we are confident that we’ll never actually hit that path in practice. If the expected behavior is “crash the program if it turns out I was wrong and the function actually does return nil,” that’s exactly the behavior you’ll get from changing the return type to (non-optional) String and replacing any nil returns with fatalError().

2 Likes

This is what I get when I return String?

So I have to force unwrap it to remove the optional keyword

so my question is why can't I return from the func -> String! To give the same output without optional keyword without having to write the extra as! String Part

Could you explain how the following modified version of getWeatherStatus differs from what you want?

func getWeatherStatus (status: weatherType ) -> String {
    switch status{
    case .cloud:
        return "It's gonna rain"
    case .sunny:
        return "It's hot"
    case .wind(let speed) where speed < 10:
        return "Not that windy"
    case .wind, .snowy:
        fatalError()
    }
}

It will give exactly the same output as I want but will not solve the issue where if we know nil is there but we know it will not be called cause then that means we don't need the ! as a whole and we can just resort to calling it without optionals

Why is it possible to do this:

let num = Int(str)!

when we can just do this:

let num = Int(str)

I was thinking why can't we apply the same logic since we are allowed to force unwrap here, then why not also allow force unwrap a return instead of only optional.

Your solution is by no means wrong but I want to know why is this not an option in the case of a func return but it is an option in many other cases.

This may not capture the sense of what you’re trying to do but the reason you can’t return String! Is because it isn’t a type. String is a type and String? is a type. String! is not.

2 Likes

Thank you, this ultimately answers my question tbh.
I am just wondering if it can be added in the future ?

cause uhh why not.. I feel like it might make some stuff easier? idk I am still new ngl

I think you are looking for this:

let weatherStatus = getWeatherStatus(status: .cloud)!

(Also, you should probably remove the argument label from the function, so the word “status” isn’t repeated twice at the call-site.)

That's def one way to do it but ultimately what I am looking for is for this

func getWeatherStatus (status: weatherType ) -> String! {
    switch status{
    case .cloud:
        return "It's gonna rain"
    case .sunny:
        return "It's hot"
    case .wind(let speed) where speed < 10:
        return "Not that windy"
    case .wind, .snowy:
        return nil
    }

}

let weatherStatus = getWeatherStatus(status: .cloud)
print(weatherStatus)

where instead of having to change the object to force unwrap I can override the default value of Optional(" Bla bla") to "bla bla" as the return for all cases that aren't nil using -> String!instead of having to do for the each object we call

Adding this adds no expressivity to the language. From the point of view of a caller of this function a return of String and a return of String! are identical - both promise a value. If the author of the function can make that promise they should return a String.

2 Likes

Implicitly unwrapped optionals used to be a separate type, but it was removed. Now, they are regular optionals with a special flag that allows implicit unwrapping. Given that it was changed from being a separate type to the status quo, and has been this way for a long time now, I don't think it is likely that reverting to the old design would be considered.

See this swift.org blog post, or the full proposal if you'd like to know the details.

The code as you've written it (returning String!) does actually compile and work. The reason you get the error is because secretly you're still dealing with an optional. It just has the special flag.

6 Likes

Fair enough I understand your pov I would love to discuss my idea a bit more but I am unable to rephrase it the correct way so I will leave it as it is for now.
Still appreciate it though

The code does actually run but it still returns optional even with the ! (Which is weird to me ngl):

but I didn't know it used to be a thing actually. Now I understand and thanks for the good discussion!

1 Like

Was writing up a post that basically just said what Karl explained re: implicitly unwrapped optionals. Implicitly unwrapped optionals only apply to the declaration to which they’re attached, and do not propagate. That is, in the line:

The type of weatherStatus is String? because the type of getWeatherStatus(status: .cloud) is String?, and there’s no type context to tell the compiler to force unwrap the result. It’s possible to write:

let weatherStatus: String = getWeatherStatus(status: .cloud)

and get the unwrapping to happen as expected. It would also happen automatically if you were, e.g., passing the function result directly as a function argument that was expected to be of type String. But absent some context that tells the compiler to convert your implicitly unwrapped optional to a non-optional value, it will naturally propagate as a normal optional.

4 Likes