6

In Swift, how is tuple related to function argument?

In the following two examples the function returns the same type even though one takes a tuple while the other takes two arguments. From the caller standpoint (without peeking at the code), there is no difference whether the function takes a tuple or regular arguments.

Is function argument related to tuple in some ways?

e.g.

func testFunctionUsingTuple()->(Int, String)->Void {
    func t(x:(Int, String)) {
        print("\(x.0) \(x.1)")
    }

    return t
}

func testFuncUsingArgs()->(Int, String)->Void {
    func t(x:Int, y:String) {
        print("\(x) \(y)")
    }

    return t
}

do {
    var t = testFunctionUsingTuple()
    t(1, "test")
}

do {
    var t = testFuncUsingArgs()
    t(1, "test")
}

There is also inconsistencies in behavior when declaring tuple in function argument in a regular function (rather than a returned function):

func funcUsingTuple(x:(Int, String)) {
    print("\(x.0) \(x.1)")
}

func funcUsingArgs(x:Int, _ y:String) {
    print("\(x) \(y)")
}

// No longer works, need to call funcUsingTuple((1, "test")) instead
funcUsingTuple(1, "test")   
funcUsingArgs(1, "test3")

UPDATED:

Chris Lattner's clarification on tuple:

"x.0” where x is a scalar value produces that scalar value, due to odd behavior involving excessive implicit conversions between scalars and tuples. This is a bug to be fixed.

In "let x = (y)”, x and y have the same type, because (x) is the syntax for a parenthesis (i.e., grouping) operator, not a tuple formation operator. There is no such thing as a single-element unlabeled tuple value.

In "(foo: 42)” - which is most commonly seen in argument lists - you’re producing a single element tuple with a label for the element. The compiler is currently trying hard to eliminate them and demote them to scalars, but does so inconsistently (which is also a bug). That said, single-element labeled tuples are a thing.

4
  • In this function func funcUsingTuple(x:(Int, String)) you have to explicitly pass a tuple: funcUsingTuple((1, "test")) Commented Jul 9, 2015 at 15:04
  • @Antonio Yes I already noted that. Question is why do I not need to do the same when the same exact function is being returned from a function instead? (See earlier example) Commented Jul 9, 2015 at 15:06
  • @Boon, seriously, not even an up-vote for each of the substantial answers with associated discussion? Commented Jul 10, 2015 at 14:22
  • 1
    @GoZoner Thanks for the reminder, there were still on=going active discussions. Upvoted your answer. Hasn't selected an answer yet because no answer has covered the second part of the question. Commented Jul 10, 2015 at 14:39

2 Answers 2

4

Every function takes exactly one tuple containing the function's arguments. This includes functions with no arguments which take () - the empty tuple - as its one argument.

Here is how the Swift compiler translates various paren forms into internal representations:

() -> Void
(x) -> x
(x, ...) -> [Tuple x ...]

and, if there was a tuple? function, it would return true on: Void, X, [Tuple x ...].

And here is your proof:

let t0 : () = ()
t0.0 // error

let t1 : (Int) = (100)
t1.0 -> 100
t1.1 // error

let t2 : (Int, Int) = (100, 200)
t2.0 -> 100
t2.1 -> 200
t2.2 // error

[Boldly stated w/o a Swift interpreter accessible at the moment.]

From AirSpeedVelocity

But wait, you ask, what if I pass something other than a tuple in? Well, I answer (in a deeply philosophical tone), what really is a variable if not a tuple of one element? Every variable in Swift is a 1-tuple. In fact, every non-tuple variable has a .0 property that is the value of that variable.4 Open up a playground and try it. So if you pass in a non-tuple variable into TupleCollectionView, it’s legit for it to act like a collection of one. If you’re unconvinced, read that justification again in the voice of someone who sounds really confident.

Remember the 'philosophical tone' as we've reached the 'I say potato; your say potato' phase.

Sign up to request clarification or add additional context in comments.

21 Comments

That doesn't seem to be the case because you cannot have a single-element tuple, and a function can take a single argument.
That is an optimization - a one tuple of X is X.
So one tuple of X is no longer a tuple? reflect(x) seems to suggest so. A tuple is an actual type, how can a single element tuple lose its type?
Check this. oneSimple becomes @_Tv4main9oneSimpleSi and oneTuple becomes @_Tv4main8oneTupleSi. Si is Swift.Int according to Mike's post. There's no T (= tuple). Which is there only for empty tuple (T_) or 2 (or more) elements TSiSi_. emptyTuple becomes @_Tv4main10emptyTupleT_ and twoTuple becomes @_Tv4main8twoTupleTSiSi_.
@Boon It's not disassembly. It's SIL (Swit Intermediate Language) and LLVM IR. Just pass -emit-sil or -emit-ir to swiftc. Compilation consists of several phases - Swift -> Swift AST -> SIL -> LLVM IR -> assembly -> binary. Why .0? Don't know the reasoning, ask Chris Lattner, but according to article written by Airspeed Velocity linked by Rob Every variable in Swift is a 1-tuple. In fact, every non-tuple variable has a .0 property that is the value of that variable. I take it as a fact for now.
|
1

A function in Swift takes a tuple as parameter, which can contain zero or more values. A parameterless function takes a tuple with no value, a function with one parameter takes a tuple with 1 value, etc.

You can invoke a function by passing parameters individually, or by grouping them into an immutable tuple. For example, all these invocations are equivalent:

do {
    let t1 = testFunctionUsingTuple()
    let t2 = testFuncUsingArgs()

    let params = (1, "tuple test")

    t1(params)
    t1(2, "test")

    t2(params)
    t2(3, "test")
}

12 Comments

A tuple has to have at least two elements. You cannot have a single element tuple. A function can take a single argument, so is the statement "A function in Swift takes a tuple as a parameter" accurate? Also, I posted example of inconsistent behavior with regular func taking tuple (vs. returned func), which is interesting.
() is a tuple - just a tuple with no value. The minimum number of values in a tuple is zero, not two - think of the () in (Int) -> (): the return value is a tuple with no value (i.e. void)
Check developer.apple.com/library/prerelease/ios/documentation/Swift/… - search for Tuple Type - A tuple type is a comma-separated list of zero or more types, enclosed in parentheses. - () no special case, empty tuple.
However let x = 1; print(x.0) works, which means x is both an Int and a tuple
Every type can be automatically promoted to a one-tuple containing that type. This is very similar to the fact that every type can be automatically promoted to an Optional of that type. Tuples and Optionals are still types; they just have promotion rules. Airspeed Velocity did an excellent writeup of tuples here: airspeedvelocity.net/2014/08/02/tuple-wrangling
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.