4

Consider the code given below

class division {
    var count: Int = 0
    func incrementBy(no1: Int, no2: Int) {
        count = no1 / no2
        println(count)
    }
}

let counter = division()
counter.incrementBy(no1:1800, no2: 3)

It gives following error :

error: extraneous argument label 'no1:' in call
counter.incrementBy(no1:1800, no2: 3)
                   ^~~~~

When I remove the label no1, compiler doesn't complain for the label no2.

When I remove both levels no1 and no2, it gives following error :

error: missing argument label 'no2:' in call
counter.incrementBy(1800,  3)
                   ^
                           no2: 

Can anyone please explain this behaviour. Thanks in advance.

Jayram Kumar
  • 682
  • 2
  • 16
  • 28

1 Answers1

11

Swift 3

The contents of this answer (written for Swift 2.2 bbelow) is all mostly still applicable, but with the difference that the following default behavior now holds in Swift 3:

  • All the function parameters have the same external parameter name as the internal one, unless otherwise specified.

I.e., the first function parameter no longer has an empty (omitted, _) external parameter name, per default, as was the case in Swift 2.2.

For additional details, see the following accepted and implemented Swift Evolution proposal:


Swift 2

Functions: external and internal parameter names

For any function in Swift, the function parameters has internal as well as external parameter names. By default, the following default behaviour holds:

  • The first function parameter has an empty (omitted, _) external parameter name.
  • All the following parameters have the same external parameter name as the internal one, unless otherwise specified.

Hence, following function

func foo(first: Int, second: Int) {}

is called as

foo(1, second: 2)
//  |     \
//  |   by default, same external as internal parameter name
//   \
//    by default, no external parameter name  

Now, you can naturally specify whether also the first function parameter should have an external name (which then needs to be specified when calling the function):

func foo(firstExternal first: Int, second: Int) {}

// called as
foo(firstExternal: 1, second: 2)

Likewise, you may specify that you want the second parameter to have no external name (omitted) by specifying the external name as an underscore _.

func foo(first: Int, _ second: Int) {}

// called as
foo(1, 2)

If we return to the first example above (default behaviour), we realize that if we specify no external names, e.g.

func foo(first: Int, second: Int) {}

we get a "default" function signature (w.r.t. external parameter names) that is the equivalence of the following explicitly stated external names:

func foo(_ first: Int, second second: Int) {}
//       |               \
//       |       same external as internal parameter name
//        \
//    no (omitted) external parameter name

For additional details, see

Your specific example

Using the knowledge from above, we can apply it to your specific example, looking only at the signature of your function incrementBy:

func incrementBy(no1: Int, no2: Int) { ... }
//               |          \
//               |    no explicitly stated external names: hence, since
//               |    this is not the first parameter, the external name
//               |    is set to the same as the internal name (no2), by default
//                \
//       no explicitly stated external names: hence, since this is the
//       first parameter, the external name is omitted, by default  

Hence, we call your function incrementBy as

incrementBy(1, no2: 2)

With this, we also realize why your two own attempts---included in your question---yields errors:

Error #1

error: extraneous argument label 'no1:' in call
counter.incrementBy(no1:1800, no2: 3)

As explained by this error message, you have an extraneous argument label for the first function argument: as covered above, the first function parameter has an omitted external parameter name by default (which is in effect in your example), and hence, when calling it, we should include no argument label for the first parameter.

Error #2

error: missing argument label 'no2:' in call
counter.incrementBy(1800,  3)

This attempted call, on the other hand, correctly omits external parameter name label for the first argument, but does so also for the second argument. The second function parameter of incrementBy, however, has the same external parameter name as its internal one, and hence, the external parameter name label no2: must be included in the call to the function.

dfrib
  • 70,367
  • 12
  • 127
  • 192
  • Above explanation is valid for methods and not for functions. – Jayram Kumar Apr 06 '16 at 06:59
  • @JayramKumar the above holds for methods as well as (global) functions. The only thing I haven't mentioned is initializers, for which all initializer parameters have, by default, the same external as internal parameter name (i.e. first parameter does not have an omitted (`_`) external name by default). – dfrib Apr 06 '16 at 08:39
  • `func foo(a:Int, b:Int) -> Int { return a + b } println(foo(2,b:3)); //error: extraneous argument label 'b:' in call`, I am using swift 1.2 – Jayram Kumar Apr 06 '16 at 10:38
  • @JayramKumar Swift 1.2 can almost be considered ancient, you should consider updating to a less old and premature version of Swift. Current Xcode 7.3 ships with Swift 2.2. – dfrib Apr 06 '16 at 11:05
  • great answer but stupid syntax design – Martin Mlostek May 24 '16 at 10:12
  • 1
    @martynmlostekk Thanks. I can agree that the syntax is, if not stupid, at least a bit inconsistent (first parameter vs rest), leading to confusion for many new Swift developers. Swift 3, however, will remedy this inconsistency whereafter external/internal parameter rules for functions will be consistent for all parameters, and hence consistent with the current rules for parameters in initializers. See [this accepted evolution proposal](https://github.com/apple/swift-evolution/blob/master/proposals/0046-first-label.md). – dfrib May 24 '16 at 10:32
  • oooh.. thats great news! thanks for sharing it! – Martin Mlostek May 24 '16 at 10:39