Why do I need to force unwrap so much?

Hello everyone,
Take this exampel:

let names = ["Zoey", "Chloe", "Amani", "Amaia"]
let randomName = names.randomElement()!


Why do I need to force unwrap this? I understand that randomElement maybe returns nil in the spec but as one can clearly see there are no chance that this will return nil.


Also this example:

[-10, 10].randomElement()

I get error: Value of optional type 'Int?' must be unwrapped to a value of type 'Int'


It makes no sense, I am sure the compiler must be smarter then this and I am making something wrong here.

Accepted Reply

Great we do not have a single opinion here.


Take care of you.


And don't forget to close the thread.

Replies

You should not unwrap like this, but test for nil:

let names = ["Zoey", "Chloe", "Amani", "Amaia"]
if let randomName = names.randomElement() {
     print(randomName)
} else {
     print("No name available")
}

brute unwrapping will result in crashes if array is empty.


Sure, compiler can always be smarter.

But what would you want ?

- randomElement to return either a value if non empty array

- return a nil if empty


Now imagine the case where names may change:


var names = ["Zoey", "Chloe", "Amani", "Amaia"]
let randomName = names.randomElement()     // Would return a value
names = []
let randomName2 = names.randomElement()     // Would return optional nil


Coding would now be very hard, as you would have to test if array is empty to know if you get optional or value.

That's essentially what returning optional is doing for you.

Well I would like the compiler to check if the array is let and then know that the value will never change.


Having to code something and say "hey this will never ever change" to the compiler and then having the compiler complain is just a waste of using the word let.


And I would like the compiler to know that there is no point to make me check for something that is impossible. (this is not one of those it's 99.9% impossible, this is 100%)


Thank you how the example for testing if a value is nil in Swift

I think you missed my point.


Yes, the compiler could do it.


But for the developer, I think the solution would be worse than the problem.

I declare

let array1 = ["Zoey", "Chloe", "Amani", "Amaia"]

var array2 = ["Claris"]

var array3 = []


a few tens lines of code, I do not see immediately if it is a const or a var.

I want to get a random in those arrays.

For the first I get a direct value : no unwrap

for the second, I get an optional, which can be nil : need for safe unwrap

for the third ?


Sure, compiler could check and find the error, but coding becomes less predictable.

I'm convinced it is a really well thought design choice. But feel free to file for an imrpovement request if you feel different.

I would argue that having to check everything when the coder has made sure it's correct is making the code less readable and then more prone to bugs.
Thank you for taking the time to discuss Swift design with me, even I if I do not agree with their choice.
I will just have to live with the choices of the developers.

Great we do not have a single opinion here.


Take care of you.


And don't forget to close the thread.

Swift is so-called a type-safe language or statically typed language, as well as many other compiler languages.

That means Swift compiler works denpending on the statically declared types.


The method `randomElement()` is declared as returning `Optional<Wrapped>` (in this case `Optional<String>`), and Swift compiler forces us unwrap it (forced or safely) when we want the wrapped value.

Even when compiler knows that `randomElement()` is used in a context that it returns non-nil value, compiler should not change the return type, which would leads to confusions.


Consider a case using Array of one element.

let names = ["Zoey"]
let theVeryName: String = names[0]


Do you think this make no sense, that we need to subscript with index 0, when it is 100% sure that the Array has only one element ?

Unwrapping is very similar to this.

You need to subscript an Array with index 0 even when 100% sure the Array has only one element, because the type is Array.

You need to unwrap an Optional even when 100% sure the Optional has non-nil value, because the type is Optional.


In the future, some compilers would appear which might be type-safe and smarter, you may study that in sort of laboratory or discuss it in swift.org .

I will just have to live with the choices of the developers.

Alternatively, you could engage with the Swift Evolution process.

As to your specific issue with

randomElement
, the force unwrap here is equivalent to an assertion that the array is not empty. Unfortunately that information is not encoded in the type system, which is why
randomElement
has to return an optional. You see similar behaviour with
first
and
last
.

You’re suggestion is for the compiler to infer that information by tracking state between statements, specifically, from the

let
on line 1 to the
randomElement
on line 2. This would be very challenging given Swift’s architecture.

A more feasible approach would be to have a collection that’s guaranteed to be non-empty. For an experiment along those lines, see swift-nonempty.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"