Why is it always possible to access the .0 element of an optional tuple in Swift?

我是研究僧i 提交于 2019-12-11 11:06:40

问题


A feature in Swift has been making me wonder for a while... see the code below:

class Clazz {
    var foo: String = "abc";
}

let foo: Int = 1
let bar: Int? = 2
let baz: Clazz? = Clazz()
let qux: Clazz = Clazz()
let quux: (Int, String)? = (1, "abc")

foo.0           //1
foo.0.0         //1
bar.0.0.0       //{Some 2} #optional
baz.0           //{{foo "abc"}} #optional
qux.0.0         //{foo "abc"}
quux.0          //{(.0 1, .1 "abc")} #optional
quux.1          //error: doesn't have a member named '1'
quux!.1         //"abc"

As I understand, it is because a tuple with only one element of type T will be treated as T rather than (T) and vice versa, so T.0 is really (T).0, which returns the first element.

What I don't understand is, if T is optional, i.e. in the case of T? or (T)?, what's the point of being always possible to access .0 and gets exactly itself? Is it an intended feature with some real usecases, or just an unavoidable by-product?

The question is not how to 'fix' it, but why it is like this.

Or, it's because I'm reading it wrong... T?.0 should actually be (T?).0?


回答1:


  • If x is a tuple then x.i returns the i-th component.
  • If x is not a tuple then x.0 is treated as (x).0 and returns x (and x.i is an error for any i > 0).

An optional is not a tuple, so x.0 returns x for any optional type. This applies to your

let quux: (Int, String)? = (1, "abc")

and therefore

quux, quux.0, quux.0.0

are all identical, and quux.1 is an error. quux! is a tuple, therefore

quux!.0 == 1
quux!.1 == "abc"

Relevant part of the documentation:

Tuple Type
...
If there is only one element inside the parentheses, the type is simply the type of that element. For example, the type of (Int) is Int, not (Int).

Update for Swift 2.1/Xcode 7.1.1: Apparently, treating any variable as a "one-element tuple" does not work anymore:

let foo: Int = 1
let bar = foo.0 // error: value of type 'Int' has no member '0'



回答2:


You asked: Why is it possible to access the .0 element of an optional tuple in Swift?

I think the answer is: it is possible to access the .0 element of an optional tuple in Swift because it is possible to access the .0 element of any type in Swift.

So you are not seeing a special behavior related to optional tuple types. You're seeing a general behavior related to tuple accessors.

So then the real question is, why is there this general behavior? Why is it in general possible to apply a .0 tuple accessor to any type in Swift? The documentation states that "the type of (Int) is Int, not (Int)", but that does not explain why this is so or why it should work the other way so that a Int can be treated as a (Int).

I am not sure why, but I suspect the answer has to do with the fact tuples are structs, and structs in general are designed to require as little as possible overhead for memory allocation, memory dereferencing, and other runtime costs. That minimum overhead is in fact zero overhead in many cases, and then in some sense the struct is the same as its contents. So if you create a value of type Foo as follows:

struct Foo<T> { let foo:T }
let myValue:Foo<Int> = Foo(foo: Int(2))

Then the resulting value myValue at runtime is in some sense represented exactly the same as a plain Int. The surrounding type information and the fact that the Int is "contained" in a Foo does not translate into some kind of runtime structure of one thing containing another or pointing to another.

So if a Foo<Int> is a Int in this sense, and a tuple is a kind of struct, then a 1-element tuple type like (Int) is a Int in the same way. Or in general, a (T) is a T. And if a (T) is a T, then for many purposes a T is also a (T). And if a T is a (T), then you should be able to access a T in the same way you can access a (T). That is why you can do x.0 for so many possible types of x.

In this explanation I have been a bit vague about the "some sense" in which a struct type or tuple type is the same as the values it contains. I've alluded to the idea that they resolve to the same runtime structure in some cases. Is it the same in all cases? I don't know. And this equivalence could also be stated in terms of the type system, rather than in terms of compiled runtime structures. So how would one specify this equivalence more precisely? I don't know. I welcome comments! :)



来源:https://stackoverflow.com/questions/26506919/why-is-it-always-possible-to-access-the-0-element-of-an-optional-tuple-in-swift

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!