0

I am trying to migrate my company app from Swift 3.0 to Swift 4.2/5, and I have an issue with the following code, related to overloading functions:

import RxSwift

typealias Something = ([Any]) -> Observable<Any?>

class SomeClass {
    static func fromObservable<TRet: Any>(_ fn: @escaping () -> Observable<TRet?>) -> Something {
        return { _ in
            return fn().map({$0 as Any?})
        }
    }
    
    static func fromObservable<T0, TRet: Any>(_ fn: @escaping (T0) -> Observable<TRet?>) -> Something {
        return { args in
            do {
                let arg = try Converter<T0>.convert(args, index: 0)
                return fromObservable({fn(arg)})(args)
            } catch let error {
                return Observable.error(error)
            }
        }
    }
}

enum MyError: Error {
    case someErr(value: Any, expected: String, actual: String, index: Int)
    case someOtherErr(args: [Any], expected: Int)
}

class Converter<T> {
    static func convert(_ arr: [Any], index: Int) throws -> T {
        guard arr.indices.contains(index) else {
            throw MyError.someOtherErr(args: arr, expected: index + 1)
        }
        
        let val = arr[index]
        guard let casted = val as? T else {
            throw MyError.someErr(value: val, expected: String(describing: T.self), actual: String(describing: type(of: val)), index: index)
        }
        
        return casted
    }
}

The code used to work fine but after migration, it throws:

error: CocoaPodsExample.playground:16:24: error: ambiguous use of 'fromObservable'
                return fromObservable({fn(arg)})(args)
                       ^

CocoaPodsExample.playground:6:17: note: found this candidate
    static func fromObservable<TRet: Any>(_ fn: @escaping () -> Observable<TRet?>) -> Something {
                ^

CocoaPodsExample.playground:12:17: note: found this candidate
    static func fromObservable<T0, TRet: Any>(_ fn: @escaping (T0) -> Observable<TRet?>) -> Something {

Also found this previous StackOverflow answer, but couldn't find any explanation or reference in Swift guides on WHY to use double parens.

  • Without digging in too deeply, I strongly suspect the problem is `Observable`. This doesn't mean "an observable of any type." It means *specifically* an Observable of `Any?`. So `Observable` would not match, unless `TRet` were `Any`. Generics are not covariant. – Rob Napier Aug 27 '20 at 20:07
  • I don't think the double-parens issue has anything to do with this. I think you just have way too many `Any` going on here, and particularly `Any?` which is a cursed type. If you find yourself needing `Any?` you're probably misusing the type system and it's going to bite you. You want to go back to what these functions are meant to do and build them without Any. – Rob Napier Aug 27 '20 at 20:13
  • @RobNapier Unfortunately, it's not possible using something else than Any - it's an abstraction that ultimately functions as an RN code bridge. I also want to point out that this code has been within the app for a long time and only started throwing compilation errors after migrating Swift 4.2. – Or Rosenblatt Aug 27 '20 at 20:47

0 Answers0