Returning `nil` from a `compactMap()` closure fails result type check
Asked Answered
R

2

6

In this snippet, I try to map [RegisteredMediaAttachment] to [BasicAttachmentInput], but only for those items that have a parseable uploadUrl.

    private func createSecondaryAttachments(
        _ attachments: [RegisteredMediaAttachment]
    ) -> [BasicAttachmentInput] {
        return attachments.compactMap {
            guard let name = URL(string: $0.registration.uploadUrl) else {
                return nil
            }

            return BasicAttachmentInput(
                name: name,
                contentType: $0.attachment.type.mime(),
                sizeBytes: $0.attachment.data.count,
                mediaId: $0.registration.media.id
            )
        }
    }

However, Swift complains on the line return nil that 'nil' is not compatible with closure result type 'BasicAttachmentInput'

This surprises me. I expect the function to compile and reduce the map result to contain only non-nil values returned from the compactMap closure. What is wrong with the snippet above?

Reconstructionist answered 25/10, 2023 at 7:23 Comment(4)
to achieve what you want, you could try this: func createSecondaryAttachments(_ attachments: [RegisteredMediaAttachment]) -> [BasicAttachmentInput] { return attachments.compactMap { if let name = URL(string: $0.uploadUrl) { return BasicAttachmentInput(.....) } } }, but to fully explain your error is more difficult.Assimilation
Is this one of those cases where Swift is not smart enough to infer the type again? Try writing all the types explicitly, attachments.compactMap { (attachment: RegisteredMediaAttachment) -> BasicAttachmentInput?Catherine
I tried your code with some simple structs ; one with an optional and one without and the function takes an array of the first and returns a compactmap containing the second. I got no errors in either playgrounds nor Xcode 15Devisal
I also tried with a string and and a url property as output. Again, no errors. Can you create a minimal reproducible example?Devisal
R
10

Turns out Swift is just failing to infer the types correctly: simply annotating the compactMap() closure with the implied return type solves the issue:

    private func createSecondaryAttachments(
        _ attachments: [RegisteredMediaAttachment]
    ) -> [BasicAttachmentInput] {
        return attachments.compactMap { (attachment: RegisteredMediaAttachment) -> BasicAttachmentInput?
            // Note the explicit return type signature of the closure above ^
            guard let name = URL(string: $0.registration.uploadUrl) else {
                return nil
            }

            return BasicAttachmentInput(
                name: name,
                contentType: $0.attachment.type.mime(),
                sizeBytes: $0.attachment.data.count,
                mediaId: $0.registration.media.id
            )
        }
    }

Reconstructionist answered 25/10, 2023 at 9:3 Comment(0)
B
5

compactMap and error

'nil' is not compatible with closure result type

Also this error is threw when you have a syntax error inside closure(which is ignored)

Berkelium answered 12/6, 2024 at 20:27 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.