Boon
Boon

Reputation: 41510

Tuple and Function Argument in Swift

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.

Upvotes: 6

Views: 4209

Answers (2)

GoZoner
GoZoner

Reputation: 70245

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.

Upvotes: 4

Antonio
Antonio

Reputation: 72810

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")
}

Upvotes: 1

Related Questions