Array of tuples in Swift
Asked Answered
E

3

14

I have a function:

func parseJSON3(inputData: NSData) -> NSArray {
    var tempDict: (id:Int, ccomments:Int, post_date:String, post_title:String, url:String) = (id: 0, ccomments: 0, post_date: "null", post_title: "null", url: "null")
    var resultArray: (id:Int, ccomments:Int, post_date:String, post_title:String, url:String)[] = []
    var error: NSError?
    var jsonDictionary: NSDictionary = NSJSONSerialization.JSONObjectWithData(inputData, options: NSJSONReadingOptions.MutableContainers, error: &error) as NSDictionary
    var firstArray = jsonDictionary.objectForKey("locations") as NSArray
    for dict in firstArray {
        tempDict.id = dict.valueForKey("ID") as Int
        tempDict.ccomments = dict.valueForKey("ccomments") as Int
        tempDict.post_date = dict.valueForKey("post_date") as String
        tempDict.post_title = dict.valueForKey("post_title") as String
        tempDict.url = dict.valueForKey("url") as String
        resultArray.append(tempDict)
    }
    return resultArray
}

In line

resultArray.append(tempDict)

I have an error:

Missing argument for parameter 'ccomments' in call

Why? Help please....

Edgar answered 13/6, 2014 at 17:18 Comment(0)
P
11

It looks to me like resultArray.append() is treating the tuple a little bit like a variadic parameter, and trying to expand the tuple to match its own arguments. It's complaining about your second parameter because it's only expecting one. I haven't seen this behavior for Array.append() documented anywhere, so I would say it's a bug in Swift.

Using the appending operator += doesn't seem to have that issue:

resultArray += tempDict
Potsherd answered 13/6, 2014 at 18:17 Comment(1)
I don't believe this describes the behavior, see my answer for some interesting results of my investigation!Danuloff
D
9

So this is pretty wild - not sure if I would qualify it as a bug or as undocumented behavior, but it's definitely something that should be on the radar for a fix / clarification!

The situation is that append is treating your argument tempDict (which we would expect to be the only argument to an Array method that takes a single member and adds it to the collection) as the first argument in a signature where it is looking for 5 arguments (!), one for each member of the Tuple type that the Array holds.

See the following for some interesting behavior (including assigning a label to the single member of a 1-member 'Tuple' ??) ->

var arrayOne: Array<String> = []
arrayOne.append("hi")
println(arrayOne[0])        // hi

var arrayTwo: Array<(String)> = []    // where (String) is a single-member Tuple
arrayTwo.append("hi")
println(arrayTwo[0])        // hi
println(arrayTwo[0].0)      // hi  -> using .0 subscript to access the first member of the Tuple

// wanna see something crazy? remember arrayOne, that holds members of type String?
println(arrayOne[0].0)      // hi  -> this Array does not hold Tuples, but it looks like we can still treat its members like "single-member Tuples"?

var arrayThree: Array<(str: String)> = []    // members of the Array are single-member Tuples with the label 'str' for their member
arrayThree.append(str: "hi")                 // now we can't use append without providing the label 'str', acting as what looks like an argument label?
var byeString = "bye"
var byeTuple = ("bye")
arrayThree += byeString     // += doesn't care about the label, and will take either a String or a single-member Tuple holding a String
arrayThree += byeTuple
println(arrayThree[0])      // hi
println(arrayThree[0].0)    // hi
println(arrayThree[0].str)  // hi  -> accessing the single member of the Tuple by its label

...so in your case, where you are seeing the error with append what it wants you to do is (using the labels you used to declare the Tuple as something that looks like argument labels):

var resultArray: (id:Int, ccomments:Int, post_date:String, post_title:String, url:String)[] = []
...
resultArray.append(id: someIntValue, ccomments: someOtherIntValue, post_date: someStringValue, post_title: someOtherStringValue, url: someAnotherStringValue)

...and of course, as discussed, you can avoid doing that by just using += instead

Crazy stuff! could be by design to serve some purpose, could be a consequence of protocol inheritance that wasn't meant to have this effect... would be interesting to know the answer!

Danuloff answered 14/6, 2014 at 23:35 Comment(1)
This is really interesting (and still happening in Beta 3). I guess it has something to do with the fact that func foo(x:Int,y:String) has the same effect as func foo((x:Int,y:String)).Rena
E
0

resultArray.append() seems to be taking tempDict as the first tuple element (id).

Changing it to :

resultArray += tempDict

seems to compile and work.

I'm not sure why append() doesn't behave the same way, maybe you can file a bug!

Euthanasia answered 13/6, 2014 at 17:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.