Access tuples by subscript
Asked Answered
P

4

9

Let's say I have this code:

let tuples = ("1", 2, "3", "4", "5", "6", "7", false)

func tableView(tableView:NSTableView, viewForTableColumn tableColumn:NSTableColumn?, row:Int) -> NSView?
{
    let valueForView = tuples[row]
}

Is there any way to access tuples by subscript?

Preach answered 14/6, 2015 at 15:10 Comment(4)
Like @Ben-G said what you want to do is not possible, use an Array instead.Sligo
How would this work? The tuple element type depends on the index, which has to be known at compile-time.Rondure
@Rondure downcast to AnyGluttony
It is possible to access by index by casting to a buffer pointer, if and only if the tuple type is homogeneous. But the only correct answer is don't use Tuples this way.Daukas
S
2

What you want is not possible with tuples and if you dont want to cast everything later-on your only option is struct or class. struct seems like a better choise :)

struct MyStruct {
    let opt1 = 0
    let opt2 = 0
    let opt3 = 0
    ...
    let boolThing = false
}
Sligo answered 14/6, 2015 at 15:23 Comment(4)
Thanks, this seems to be the most useful answer.Preach
Good answer! However, you unfortunately also won't be able to make this subscriptable and type-safe :(Alannaalano
Yes i noticed that and was a little chocked with the accept :O But perhaps my answer gave OP an idea :)Sligo
No, I went with using an array and casting after all but haven't thought about structs in this case at all. ;)Preach
A
11

No, you can only access tuple elements by directly specifying the index, e.g.

tuples.5

For your purpose you should simply use an array.

Alannaalano answered 14/6, 2015 at 15:17 Comment(6)
But that array would have to be [AnyObject] for mixed types. The tuple would allow for typed access of its values.Preach
@hexagonstar User a struct then ;)Sligo
Wonder if there isn't a way to extend Swift Tuple with subscript extensions?Preach
@hexagonstar, you would have to solve the same problem within that extension.Freewill
Tuples are part of the programming language and not of the Standard Library so I don't think we can extend the type. Until the compiler is Open Source at least ;)Alannaalano
It's open source @Ben-G.Gluttony
B
5

It is kind of possible using reflection:

Mirror(reflecting: tuples).children[AnyIndex(row)].value
Byronbyrum answered 4/10, 2016 at 10:38 Comment(1)
Brilliant answer but sadly "subscript is get-only".Gluttony
V
4

This actually is possible if you're willing to make a wrapper around your tuple. That being said, this is terrible, don't ever do this. The suggestions made in the other answers are practically a lot better, but for education purposes, here's my example.

struct TupleWrapper {
    let tuple: (String, Int, String, String, String, String, String, Bool)    
    let count: Int
    private let mirrors: [MirrorType]

    subscript (index: Int) -> Any {
        return mirrors[index].value
    }

    init(tuple: (String, Int, String, String, String, String, String, Bool)) {
        self.tuple = tuple

        var mirrors = [MirrorType]()
        let reflected = reflect(tuple)

        for i in 0..<reflected.count {
            mirrors.append(reflected[i].1)
        }

        self.mirrors = mirrors
        self.count = mirrors.count
    }
}

let wrapper = TupleWrapper(tuple: ("1", 2, "3", "4", "5", "6", "7", false))
wrapper[0] // "1"
wrapper[wrapper.count - 1] // false

The code above uses Swift's reflection APIs to get the logical children of your tuple object and add their mirrors to an array on which we can subscript for each mirror's value. This is fairly straight forward, but as you'd expect, since we're working with tuples here, this can't really be made dynamic in any way. The wrapper has to be made for a specific tuple type.

For some related reading, see NSHipster's recent MirrorType article.

Viewable answered 14/6, 2015 at 17:32 Comment(1)
Wow, thanks but is this not the answer I'm looking for. Sadly Swift is importing a simple C Array as a fkin tuple..Vullo
S
2

What you want is not possible with tuples and if you dont want to cast everything later-on your only option is struct or class. struct seems like a better choise :)

struct MyStruct {
    let opt1 = 0
    let opt2 = 0
    let opt3 = 0
    ...
    let boolThing = false
}
Sligo answered 14/6, 2015 at 15:23 Comment(4)
Thanks, this seems to be the most useful answer.Preach
Good answer! However, you unfortunately also won't be able to make this subscriptable and type-safe :(Alannaalano
Yes i noticed that and was a little chocked with the accept :O But perhaps my answer gave OP an idea :)Sligo
No, I went with using an array and casting after all but haven't thought about structs in this case at all. ;)Preach

© 2022 - 2024 — McMap. All rights reserved.