Argo: Cannot convert value of type ... to expected argument type '(_) -> (_) -> ...

I took over a code base from a team of developers and I noticed they were using your library for Swift version 2.2. When I upgraded the code base to Swift 3 and cloned your master I’m getting this error message. I’d appreciate if I can get some insight since it’s not using Curry(JobFeedResponse.init). This is the error message the compiler is complaining about:

Error Messages

Cannot convert value of type '(Int, String, [JobFeedItem]?) -> JobFeedResponse' to expected argument type '(_) -> (_) -> (_) -> JobFeedResponse'

Any help would be appreciated.

Models

struct JobFeedResponse
{
    let jobs: [JobFeedItem]?
    let offset: Int
    let posterPath: String
}

extension JobFeedResponse: Decodable
{
    static func create(_ offest: Int, _ posterPath :String, _ jobs: [JobFeedItem]?) -> JobFeedResponse { 
        return JobFeedResponse(jobs: jobs,offset: offest, posterPath: posterPath)
    }

    static func decode(_ json: JSON) -> Decoded<JobFeedResponse> { 
        return JobFeedResponse.create
            <^> json <| ["response", "offset"]
            <*> json <| ["response", "posterPath"]
            <*> json <||? ["response", "jobs"]
    }
}

Argo Version

Argo (master) - Swift 3

Dependency Manager

Carthage

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 17 (3 by maintainers)

Most upvoted comments

I changed the order as you requested and still getting this error

struct JobFeedResponse
{
    let offset: Int
    let posterPath: String
    let jobs: [JobFeedItem]?
}

extension JobFeedResponse: Decodable
{
    static func create(_ offest: Int, _ posterPath :String, _ jobs: [JobFeedItem]?) -> JobFeedResponse { 
        return JobFeedResponse(offset: offest, posterPath: posterPath,jobs: jobs)
    }

    static func decode(_ json: JSON) -> Decoded<JobFeedResponse> { 
        return JobFeedResponse.create
            <^> json <| ["response", "offset"]
            <*> json <| ["response", "posterPath"]
            <*> json <||? ["response", "jobs"] 
    }
}

and I’m still getting the same error. I’ll do some digging and get to the bottom of this.

Great! Glad it worked out for you.

For reference: You could also avoid the Curry dependency if you really wanted to by writing your create function to be explicitly curried, but it would be ugly:

  static func create(_ id: String) -> (String) -> (String) -> (String) -> (String?) -> (String) -> (String) -> ([Opentime]?) -> Venue {
    return { id in
      { lat in
        { lng in
          { name in
            { distance in
              { address in
                { timezone in
                  { opentimes in
                    let latFloat = (lat as NSString).doubleValue
                    let lngFloat = (lng as NSString).doubleValue
                    let coordinate = CLLocationCoordinate2DMake(latFloat, lngFloat)
                    var distanceFloat = 0.0
                    if distance != nil {
                      distanceFloat = (distance! as NSString).doubleValue
                    }

                    return Venue(id: Int(id)!, coordinate: coordinate, name: name, address: address, distance: distanceFloat, timezone: timezone, opentimes: opentimes)
                  }
                }
              }
            }
          }
        }
      }
    }
  }

This is why we wrote Curry.framework in the first place.

Some more thoughts/tips:

It seems like your JSON response isn’t really sending the data you want. Is this an API you control? Some things that could be improved on the API side:

  • Right now you’re decoding id to a string and then forcing it to an Int. Is there a reason that the API can’t send this as an Int from the start? Alternatively, if your API is sending IDs as strings maybe it’s best to store them as strings?
  • We could clean up the CLLocation stuff really easily if the API were to send the lat/long in a nested key ("location": {"lat": 1234, "lng": 1234}}) instead of inline. If that were the case, then we could make CLLocation conform to Decodable and we’d be able to extract the logic around decoding that type appropriately. And as with the ID, I’d wonder why the API was sending these back as strings instead of ints.

In any case, I might still move towards removing the need for your create function entirely by adding some info to your parser (Note that most of the complexity in this parser comes from the mistyped API):

struct Venue {
  let id :Int
  let coordinate: CLLocationCoordinate2D
  let name :String
  let address :String
  let distance :Double
  let timezone :String

  let opentimes :[Opentime]?

  func getFormattedDistance() -> String {
    let roundedDistance = Double(round(100*distance)/100)
    return "\(roundedDistance) Mi."
  }
}

extension Venue: Decodable {
  static func decode(_ j: JSON) -> Decoded<Venue> {
    return curry(Venue.init)
    <^> j <| "id" >>- intFromString
    <*> decodeLocation(j)
    <*> j <| "name"
    <*> j <| "address"
    <*> (j <| "distance" >>- doubleFromString) <|> pure(0.0)
    <*> j <| "timezone"
    <*> j <||? "opentimes"
  }

  private static func doubleFromString(_ string: String) -> Decoded<Double> {
    let double = (string as NSString).doubleValue
    return pure(double)
  }

  private static func intFromString(_ string: String) -> Decoded<Int> {
    return .fromOptional(Int(string))
  }

  private static func decodeLocation(_ json: JSON) -> Decoded<CLLocationCoordinate2D> {
    return curry(CLLocationCoordinate2DMake)
      <^> json <| "lat" >>- doubleFromString
      <*> json <| "lng" >>- doubleFromString
  }
}

Happy to answer any questions you have about this.