46

say I have a function that has non-default parameter after default parameter like this:

func f(first:Int = 100, second:Int){}

how can I call it and use the default value for the first parameter?

CarmeloS
  • 7,868
  • 8
  • 56
  • 103

4 Answers4

78

The current compiler does allow default parameters in the middle of a parameter list.

screenshot of Playground

You can call the function like this if you want to use the default value for the first parameter:

f(1)

If you want to supply a new value for the first parameter, use its external name:

f(first: 3, 1)

The documentation explains that parameters with a default value are automatically given an external name:

Swift provides an automatic external name for any defaulted parameter you define, if you do not provide an external name yourself. The automatic external name is the same as the local name, as if you had written a hash symbol before the local name in your code.

nathan
  • 5,466
  • 3
  • 27
  • 24
  • 1
    While this answer is technically correct and you can do it this way in Swift, it is very confusing and should be avoided. Refactoring a function to have default parameters at the end isn’t that much work. Even in this simple case it isn’t completely clear what the call to `f(1)` means. [@Connor’s answer](http://stackoverflow.com/a/24102938/133166) should be the accepted one. – Rafael Bugajewski Jan 18 '16 at 08:00
  • 2
    @Rafael I didn't say this was the best practice; I answered the question correctly. Therefore, this should be the accepted answer. – nathan Jan 19 '16 at 19:41
18

You should have the default parameters at the end of the parameter list.

func f(second:Int, first:Int = 100){}
f(10)

Place parameters with default values at the end of a function’s parameter list. This ensures that all calls to the function use the same order for their non-default arguments, and makes it clear that the same function is being called in each case.

Documentation link

Connor Pearson
  • 63,902
  • 28
  • 145
  • 142
  • so Using parameter with a default value before those without is meaningless? Why isn't it a compile time error? – CarmeloS Jun 08 '14 at 04:19
  • 1
    No it's not meaningless, it just not "ensures that all calls to the function use the same order for their non-default arguments". It will work, but could be confusing. So Apple defined a guideline to developers about where to put parameters with default values. – Mac_Cain13 Sep 17 '14 at 05:56
5

On Swift 3:

func defaultParameterBefore(_ x: Int = 1, y: Int ) {}

Calling

defaultParameterBefore(2)

will raise this error

error: missing argument for parameter 'y' in call

The only exception is:

  • There is a parameter before the default parameter;
  • and the parameter after the default parameter is a closure;
  • and the closure parameter is the last parametr;
  • and calling via trailing closure

For example:

func defaultParameterBetween(_ x: Int, _ y: Bool = true, _ z: String) {
    if y {
       print(x)
    } else
       z()
    }
}

// error: missing argument for parameter #3 in call
// defaultParameterWithTrailingClosure(1, { print(0) }

// Trailing closure does work, though.
func defaultParameterWithTrailingClosure(_ x: Int, y: Bool = true,
                                     _ z: () -> Void) {
    if y {
        print(x)
    } else {
        z()
    }
}

defaultParameterWithTrailingClosure(1) { print(0) }

swift version: DEVELOPMENT-SNAPSHOT-2016-04-12

weakish
  • 28,682
  • 5
  • 48
  • 60
0

If it is a method on a class, you need to call it like this

class Test
{
    func f(first:Int = 100, second:Int)
    {
        println("first is \(first)")
        println("second is \(second)")
    }

    func other()
    {
        f(second: 4)
        f(first: 30, second: 5)
        //f(4) will not compile, and neither will f(9,12)
    }
}

If the function f is global, you need to call it like this:

f(4)
f(first: 30, 5)

This prints:

first is 100
second is 4
first is 30
second is 5
Millie Smith
  • 4,536
  • 2
  • 24
  • 60
  • Technically you don't need a label on the required parameter. – nathan Jun 08 '14 at 04:31
  • Yes you do. I tried it without the label and it won't compile. – Millie Smith Jun 08 '14 at 04:31
  • See the screenshot in my answer. – nathan Jun 08 '14 at 04:32
  • I see it. Still doesn't compile on my box. You're using "run as I type". Maybe that's why. – Millie Smith Jun 08 '14 at 04:33
  • I get "Cannot convert the expression's type '()' to '(first: Int, second: Int)'". – Millie Smith Jun 08 '14 at 04:34
  • What version of Swift are you using? `/Applications/Xcode6-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift --version` It compiles for me on swift-600.0.34.4.5 – nathan Jun 08 '14 at 04:35
  • Swift version 1.0 (swift-600.0.34.4.5) Target: x86_64-apple-darwin13.2.0 – Millie Smith Jun 08 '14 at 04:39
  • `f(4)` works for me in the REPL and in a Playground (after pasting in your code sample). Are you sure you didn't type something wrong? – nathan Jun 08 '14 at 04:42
  • I'm human, but I'm pretty damn sure. I believe you though. What version do you have? And this "playground" that people speak of... Is that a REPL in XCode or is it actual code in a project in Xcode? – Millie Smith Jun 08 '14 at 04:44
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/55267/discussion-between-undefined-and-millie-smith). – nathan Jun 08 '14 at 04:48
  • `f(second: 4)` shouldn't work as you didn't specify externalParamName. I bet you are using it as a method of a class and not indicating it here. – Infinity Jun 08 '14 at 04:50