13

I'm learning about default arguments and I ran aground of something weird:

import UIKit

func greet(name: String = "world") {
    println("hello \(name)")
}

greet("jiaaro")

this throws an error:

Playground execution failed: error: <REPL>:9:7: error: missing argument label 'name:' in call
greet("jiaaro")
      ^
      name:

I understand that it wants greet(name: "jiaaro") but I don't understand why that should be necessary.

Jiaaro
  • 74,485
  • 42
  • 169
  • 190
  • possible duplicate of [Swift : missing argument label 'xxx' in call](http://stackoverflow.com/questions/24050844/swift-missing-argument-label-xxx-in-call) – jtbandes Jul 18 '14 at 00:43
  • @jtbandes this question is older, and I posted a link to it (in the comments) on the question you linked when that question was first asked (6 minutes after to be precise ;) – Jiaaro Jul 18 '14 at 15:35

3 Answers3

14

Swift functions can specify local and external argument names:

func greet(who name: String = "world") {
    println("hello \(name)")
}

// prints "hello world"
greet()

// prints "hello jiaaro"
greet(who:"jiaaro")

// error
greet("jiaaro")

// error
greet(name: "jiaaro")

To opt out of this behavior you can use an underscore for the external name. Note that the first parameter implicitly uses the "no external name" behavior:

func greet(name: String = "world", _ hello: String = "hello") {
    println("\(hello) \(name)")
}

// prints "hello world"
greet()

// prints "hello jiaaro"
greet("jiaaro")

// prints "hi jiaaro"
greet("jiaaro", "hi")

// error
greet(name: "jiaaro")

The following is now disallowed in Swift 2.0, see below for equivalent code.

You can use the # prefix to use the same local and external name for the first parameter:

func greet(#name: String = "world", hello: String = "hello") {
    println("\(hello) \(name)")
}

// prints "hi jiaaro"
greet(name: "jiaaro", hello: "hi")

Swift 2.0 code:

func greet(name name: String = "world", hello: String = "hello") {
    println("\(hello) \(name)")
}

// prints "hi jiaaro"
greet(name: "jiaaro", hello: "hi")
Sandy Chapman
  • 11,133
  • 3
  • 58
  • 67
Jiaaro
  • 74,485
  • 42
  • 169
  • 190
  • 1
    what's the difference between these two lines? // prints "hello jiaaro" greet("jiaaro") // error greet("jiaaro") – Sam B Jun 05 '14 at 03:01
  • @SamBudda Oops… copy/paste error - I had to keep retyping this stuff because the playground was crashing on me. Overlooked that on the 3rd or 4th time re-making the example :) – Jiaaro Jun 05 '14 at 14:17
  • XCode 6.1 no longer requires a name label for the first argument. In fact you get a warning if you use a label: Extraneous '_' in parameter: 'name' has no keyword argument name – Mike Lischke Oct 19 '14 at 13:59
  • @MikeLischke ok, thanks. So methods and functions now have the same behavior? – Jiaaro Oct 20 '14 at 18:04
3

Swift requires argument labels by default, because it supports classes with multiple initializers. The benefit of argument labels comes from the ability of Swift to infer which initializer to use; not only by argument type, but argument name as well.

struct Celsius {
    var temperatureInCelsius: Double = 0.0

    init(fromFahrenheit fahrenheit: Double) {
        temperatureInCelsius = (fahrenheit - 32.0) / 1.8
    }

    init(fromKelvin kelvin: Double) {
        temperatureInCelsius = kelvin - 273.15
    }
}

let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
// boilingPointOfWater.temperatureInCelsius is 100.0

let freezingPointOfWater = Celsius(fromKelvin: 273.15)
// freezingPointOfWater.temperatureInCelsius is 0.0

See this page for more details: https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/Swift_Programming_Language/Initialization.html#//apple_ref/doc/uid/TP40014097-CH18-XID_272

HZN
  • 77
  • 2
  • 11
1

I just wanted to add that now your code

func greet(name: String = "world") {
    print("hello \(name)")
}

greet("jiaaro")

works fine in xcode, i just changed "println" with "print"

TmSmth
  • 450
  • 5
  • 31