6

I wish to Create a Swift Method Equivalent to

+ (void)insertFileWithService:(GTLServiceDrive *)service
                    title:(NSString *)title

When I type

func insertFileWithService(service: GTLServiceDrive,
    title title: String,

I get a warning title title can be expressed more succinctly as #title

But when I change it to func insertFileWithService(service: GTLServiceDrive, #title: String

I get a warning extraneous '#' in parameter title is already the keyword argument name

Should I ignore these warnings and chalk it up to a bug in Beta ?

Ryan Heitner
  • 13,119
  • 6
  • 77
  • 119
  • So if you do: `func insertFileWithService(service: GTLServiceDrive, #title: String)` you get that warning? – Firo Jun 10 '14 at 14:29
  • 3
    Is it a function or a method? See http://stackoverflow.com/a/24046893/390581 — they behave differently. – Jean-Philippe Pellet Jun 10 '14 at 14:29
  • Yeah, I can reproduce this if the function's a class member rather than a global. Ryan, you might want to expand your question to show a minimum complete example. But I'd say it's an Xcode bug. – Matt Gibson Jun 10 '14 at 14:33
  • @MattGibson, well in that he can just remove the `#` (as recommended by Bill), right? – Firo Jun 10 '14 at 14:37
  • @Firo Well, yeah, but I'm guessing Ryan knows that. Probably the important thing here is to raise a Radar with Apple with a decent reproduction. – Matt Gibson Jun 10 '14 at 14:39
  • I experienced the same... the docs says you may use `#` for each parameter, so I guess that is a bug in the compiler. – holex Jun 10 '14 at 14:42
  • 1
    Jean-Philippe It is a method - I have updated my question thanks – Ryan Heitner Jun 10 '14 at 14:51
  • FYI I still see the exact behavior in Xcode 6.3.2 -- I add # based on the first warning, then I get the second warning. I remove the #, however, and the warning about '#' not being needed is still there, even though there is no '#'! I did a clean build and restarted Xcode and it finally "forgot" about the warning.... – rholmes Jun 03 '15 at 13:24

4 Answers4

5

I do not believe this is a bug, in fact, this is how the language was designed to work:


From Apple's Stuff (https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Methods.html#//apple_ref/doc/uid/TP40014097-CH15-XID_300):

class Counter {
    var count: Int = 0
    func incrementBy(amount: Int, numberOfTimes: Int) {
        count += amount * numberOfTimes
    }
}

This incrementBy method has two parameters—amount and numberOfTimes. By default, Swift treats amount as a local name only, but treats numberOfTimes as both a local and an external name. You call the method as follows:

let counter = Counter()
counter.incrementBy(5, numberOfTimes: 3)
// counter value is now 15

You don’t need to define an external parameter name for the first argument value, because its purpose is clear from the function name incrementBy. The second argument, however, is qualified by an external parameter name to make its purpose clear when the method is called.

This default behavior effectively treats the method as if you had written a hash symbol (#) before the numberOfTimes parameter


Basically, for Methods inside a class, the first parameter defaults to an internal parameter name only. All subsequent parameter names default to external names where the external name is the parameter name by default. Thus, the # is redundant.

func insertFileWithService(service: GTLServiceDrive, title: String)

Is equivalent to

func insertFileWithService(service: GTLServiceDrive, #title: String)

For Methods, not for Functions. This is why you are getting a warning.

jacobhyphenated
  • 2,105
  • 2
  • 17
  • 27
  • I found this in the book “If you want to provide an external parameter name for a function parameter, and the local parameter name is already an appropriate name to use, you do not need to write the same name twice for that parameter. Instead, write the name once, and prefix the name with a hash symbol (#). This tells Swift to use that name as both the local parameter name and the external parameter name.” Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. https://itunes.apple.com/il/book/swift-programming-language/id881256329?mt=11 – Ryan Heitner Jun 10 '14 at 14:54
  • Does that only apply to functions and not methods if I understand you correctly – Ryan Heitner Jun 10 '14 at 14:56
  • Correct, the quote you have is for functions not for methods. For methods, the local parameter name is assumed to be the external parameter name for all parameters except the first one. See the quoted text from my post. For methods, the # is implicit for the second parameter, which is why you are getting the warning, adding the `#` is unnecessary and the compiler wants you to be sure you know what you are trying to accomplish. – jacobhyphenated Jun 10 '14 at 14:59
  • Thank you from the complete explanation. – Ryan Heitner Jun 10 '14 at 15:02
0

Leave the hash mark off and just use "title: String"

Bill
  • 44,502
  • 24
  • 122
  • 213
0

Swift allows you to name arguments differently inside the function than out.

You'd use these "External Parameter Names" when when you wanted the argument to have a different name inside the function. From the book:

Sometimes it’s useful to name each parameter when you call a function, to indicate the purpose of each argument you pass to the function.

If you want users of your function to provide parameter names when they call your function, define an external parameter name for each parameter, in addition to the local parameter name.

Since you're using the same name both internally an externally here, "title," you can skip the external parameter name as Swift suggests and use the # prefix to denote a named external parameter with the same name referenced internally.

Example from the book:

func containsCharacter(#string: String, #characterToFind: Character) -> Bool {
    for character in string {
        if character == characterToFind {
            return true
        }
    }
    return false
}
buley
  • 28,032
  • 17
  • 85
  • 106
  • This very example will give out error, "Extraneous '#' in parameter: 'characterToFind' is already the keyword argument name" at the time of writing. – Genki Oct 28 '14 at 16:09
0

Name your method like so:

@objc(insertFileWithService:title:)
func insertFile(service: GTLServiceDrive, title: String)

Then from Swift, call it like so:

obj.insertFile(serviceDrive, title: "Title")

And in Objective C:

[obj insertFileWithService:serviceDrive title: @"Title"];
Léo Natan
  • 56,823
  • 9
  • 150
  • 195