jgvb
jgvb

Reputation: 304

How can I achieve overloading both generic and non-generic function signatures for optionals in Swift 5.1 (Xcode 11 Playground)?

import Foundation

enum Errors: Error {
    case badParse
}

public typealias JSONDictionary = [String: Any]

public func decode(_ dictionary: JSONDictionary, key: String) throws -> URL {

    guard let string = dictionary[key] as? String else {
        throw Errors.badParse
    }

    if let url = URL(string: string) {
        return url
    }

    throw Errors.badParse
}

public func decode<T>(_ dictionary: JSONDictionary, key: String) throws -> T {

    guard let value = dictionary[key] else {
        throw Errors.badParse
    }

    guard let attribute = value as? T else {
        throw Errors.badParse
    }

    return attribute
}

let url: URL = try decode(["url":"test/url"], key: "url") // url: test/url
let urlOptional: URL? = try? decode(["url":"test/url"], key: "url") // nil

The above code works as long as you're decoding a NON-optional. The specific non-generic decode function is called and the URL is constructed.

However, if you have an optionally type variable and decode it, it will not use the correct function. In swift 4.2, both optionals and non optionals would use the correct non-generic function, but since I updated to Xcode 11 swift 5.1, this behavior has been seen.

Any help would be greatly appreciated!

I would prefer not to make function signatures with optional returns such as

public func decode(_ dictionary: JSONDictionary, key: String) throws -> URL? {

because it is not scalable...and it used to work without it.

Upvotes: 1

Views: 46

Answers (1)

Sweeper
Sweeper

Reputation: 272845

Evidently, how type inference works changed a little bit in Swift 5. If you just want it to use the correct overload, you just need to give it a little push:

let urlOptional: URL? = try? decode(["url":"test/url"], key: "url") as URL

by adding as URL at the end.

Upvotes: 1

Related Questions