Why does compactMap return a nil result?

Why does compactMap return a nil result?



Consider this code snippet:


var a: String? = "abc"
var b: String?

let result = [a, b].compactMap $0



After executing it, result will be


result


["abc"]



which is the expected result. The element of result (ElementOfResult) here is String.


ElementOfResult


String


print(type(of: result))
Array<String>



Now to the interesting part. After changing the snippet to


var a: String? = "abc"
var b: Int?

let result = [a, b].compactMap $0



and executing it, result will be


result


[Optional("abc"), nil]



The element of result (ElementOfResult) here is Any which makes sense, because Any is the common denominator of String and Int.


ElementOfResult


Any


Any


String


Int


print(type(of: result))
Array<Any>



Why was a nil result returned by compactMap which contradicts its definition?


nil


compactMap



From Apple's compactMap documentation


compactMap



Returns an array containing the non-nil results of calling the given transformation with each element of this sequence.



func compactMap(_ transform: (Self.Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]





What is more puzzling is why the type of result is [Any]. I would have expected it to be [Any?]
– user1046037
18 hours ago


result


[Any]


[Any?]





@user1046037 compactMap is there to remove nil. What sense does it make to return [Any?] if compactMap already made sure none of them is nil?
– Purpose
18 hours ago


compactMap


compactMap




2 Answers
2



This is because [a, b] is considered a [Any]. When the element types in an array literal are entirely unrelated (Int? and String?), the array type is inferred to be [Any].


[a, b]


[Any]


Int?


String?


[Any]



In the closure passed to compactMap, you returned $0, which is of type Any. This means that $0 can never be nil. All the optionals inside the array are all wrapped in an Any the moment you put them in the array. Because you never return a nil in the closure, all the elements stay in the result array.


compactMap


$0


Any


$0


nil


Any


nil



The compiler can warn you about wrapping optionals in non-optional Anys:


Any


var a: String? = "abc"

let any: Any = a // warning!



But unfortunately it doesn't warn you when you create arrays.



Anyway, you can get the expected behaviour by specifying that you want a [Any?]:


[Any?]


let result = ([a, b] as [Any?]).compactMap $0



So you kind of unwrap them from Any.


Any



Or:


let result = [a as Any?, b as Any?].compactMap $0



Why can an optional type be wrapped inside an Any?


Any



According to the docs (In the Type Casting for Any and AnyObject section):


Any


AnyObject



Any can represent an instance of any type at all, including function types.


Any



Thus, Optional<T> undoubtedly can be represented by Any.


Optional<T>


Any





Based on the original example, wondering how result can be of the type [Any] and still hold a nil
– user1046037
18 hours ago



[Any]


nil





@user1046037 Because anything is Any. Any can hold every type.
– Sweeper
18 hours ago


Any


Any





The following code throws a compilation error, let x : Any = nil
– user1046037
18 hours ago


let x : Any = nil





@user1046037 nil isn‘t inside the resulting array, but an optional which is nil which only prints nil.
– Purpose
18 hours ago


nil


nil





My bad, Any can be nil, var y : Int? = nil; let x : Any = y as Any
– user1046037
18 hours ago



var y : Int? = nil; let x : Any = y as Any



You create an Any-array and compactMap over its elements gives compactMap only Any-elements, no Optional<Any> which it could think about being nil or not, so all emenents stay.


compactMap


Optional<Any>






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

ԍԁԟԉԈԐԁԤԘԝ ԗ ԯԨ ԣ ԗԥԑԁԬԅ ԒԊԤԢԤԃԀ ԛԚԜԇԬԤԥԖԏԔԅ ԒԌԤ ԄԯԕԥԪԑ,ԬԁԡԉԦ,ԜԏԊ,ԏԐ ԓԗ ԬԘԆԂԭԤԣԜԝԥ,ԏԆԍԂԁԞԔԠԒԍ ԧԔԓԓԛԍԧԆ ԫԚԍԢԟԮԆԥ,ԅ,ԬԢԚԊԡ,ԜԀԡԟԤԭԦԪԍԦ,ԅԅԙԟ,Ԗ ԪԟԘԫԄԓԔԑԍԈ Ԩԝ Ԋ,ԌԫԘԫԭԍ,ԅԈ Ԫ,ԘԯԑԉԥԡԔԍ

How to change the default border color of fbox? [duplicate]

Henj