67

I have this Function in a class:

func multiply(factor1:Int, factor2:Int) -> Int{
    return factor1 * factor2
}

I try to call the function using this:

var multResult = calculator.multiply(9834, 2321)

The problem is that the compiler wants it to look more like this:

var multResult = calculator.multiply(9834, factor2: 2321)

Why does the first one cause an error?

Jean-Philippe Pellet
  • 59,296
  • 21
  • 173
  • 234
67cherries
  • 6,931
  • 7
  • 35
  • 51
  • 1
    Looks like the compiler thinks the function is a method. – CrimsonChris Jun 04 '14 at 19:30
  • Does the class inherent from a Cocoa class (e.g. `NSObject`)? Is it marked with `@objc`? If so, the compiler assumes it may be called from Objective-C, so its methods must be of a form that's compatible with Objective-C method calling/naming conventions. – Ken Thomases Jun 04 '14 at 20:11
  • 2
    no, it's a root class (no superclass) and it is not marked with @objc. – 67cherries Jun 04 '14 at 20:14
  • it is possible to make the second arg name optional, just put `_` in front of `factor2`, e.g. `func multiply(factor1:Int, _ factor2:Int) {...}`. – Hlung Apr 18 '15 at 07:00
  • 1
    If you don't like having to enter parameter names you can replace `func multiply(factor1:Int, factor2:Int)` with `func multiply(factor1:Int, _ factor2:Int)` This is NOT a hack, but official language syntax – Jacob R Jul 03 '15 at 13:21

6 Answers6

116

Update for Swift 2.0: Now functions behave identically to methods, and for both, by default:

  • the first parameter has no external name; and
  • the other parameters have an external name identical to the internal name.

Other than that, the rules below still apply, except that the # shorthand syntax is now gone.


Here's a more general answer: functions behave differently when defined as true functions outside a class, and when defined as methods. Moreover, init methods have a special rule.


Functions

Suppose you define this:

func multiply1(f1: Double, f2: Double) -> Double {
    return f1 * f2
}

Parameter names are here only local to the function, and cannot be used when calling the function:

multiply1(10.0, 10.0)

If you want to force using named parameters when calling the function, you can. Prefix each parameter declaration with its external name. Here, the external name of f1 is f1param, and for f2, we use the shorthand where we prefix it by # to indicate that the local name is to be used as the external name as well:

func multiply2(f1param f1: Double, #f2: Double) -> Double {
    return f1 * f2
}

Then, named parameters must be used:

multiply2(f1param: 10.0, f2: 10.0)

Methods

Things are different for methods. By default, all but the first parameter are named, as you've discovered. Suppose we have this, and consider the multiply1 method:

class Calc {
    func multiply1(f1: Double, f2: Double) -> Double {
        return f1 * f2
    }
    func multiply2(f1param f1: Double, f2: Double) -> Double {
        return f1 * f2
    }
    func multiply3(f1: Double, _ f2: Double) -> Double {
        return f1 * f2
    }
}

Then, you have to use the name of the second (and following, if any) parameters:

let calc = Calc()
calc.multiply1(1.0, f2: 10.0)

You can force to use a named param for the first argument by providing an external name for it, like for functions (or prefixing its local name with # if you want to use the same external name as its local name). Then, you have to use it:

calc.multiply2(f1param: 10.0, f2: 10.0)

Finally, you can declare an external name of _ for the other following arguments, indicating that you want to call your method without using named parameters, like this:

calc.multiply3(10.0, 10.0)

Interoperability note: If you prefix class Calc with the @objc annotation, then you can use it from Objective-C code, and it is equivalent to this declaration (look at parameter names):

@interface Calc
- (double)multiply1:(double)f1 f2:(double)f2;
- (double)multiply2WithF1param:(double)f1 f2:(double)f2;
- (double)multiply3:(double)f1 :(double)f2;
@end

Init Methods

The rule differs a bit for init methods, where all parameters have an external name by default. For instance, this works:

class Calc {
    init(start: Int) {}
    init(_ start: String) {}
}

let c1 = Calc(start: 6)
let c2 = Calc("6")

Here, you have to specify start: for the overload that accepts an Int, but you must omit it for the overload that accepts a String.

Interoperability note: this class would get exported to Objective-C like this:

@interface Calc
- (instancetype)initWithStart:(NSInteger)start __attribute__((objc_designated_initializer));
- (instancetype)init:(NSString *)start __attribute__((objc_designated_initializer));
@end

Closures

Assume you define a closure type like this:

typealias FancyFunction = (f1: Double, f2: Double) -> Double

The parameter names will behave very similar to those in a method. You will have to provide the names to the parameters when calling the closure unless you explicitly set the external name to _.

For example, executing the closure:

fund doSomethingInteresting(withFunction: FancyFunction) {
    withFunction(f1: 1.0, f2: 3.0)
}

As a rule of thumb: even if you dislike them, you should probably try to keep using named parameters at least whenever two parameters have the same type, in order to disambiguate them. I'd also argue that it's good to also name at least all Int and Boolean parameters.

Jean-Philippe Pellet
  • 59,296
  • 21
  • 173
  • 234
  • 1
    I’ve added interoperability notes and the rules for `init` methods. – Jean-Philippe Pellet Jun 10 '14 at 12:48
  • But what is the difference between multiply1(f1: Double) and multiply1(f1param: Double)? Obviously the name of the parameter is different but why would that matter? – Kokodoko Jul 28 '14 at 14:51
  • It doesn’t. You just have to use whatever name you define. – Jean-Philippe Pellet Jul 28 '14 at 15:33
  • 1
    Just one more interesting thing, if you want to show the first parameter name when using the method, you have to define it like this: func method(#firstParameter: type, secondParameter: Type) Doing this, when calling the fun it will appear like that: self.method(firstParameter: 3, secondParameter: 5) If you don't add the # it will appear like that: self.method(3, secondParameter: 5) – diegomen Oct 27 '14 at 09:24
  • 2
    But what is the rationale behind this design? Is it trying to prevent us from confusing the order of parameters? If so, why doesnt a function have such limitation? – MK Yung Jun 10 '15 at 01:40
  • This is better than the official documentation. Thank you for this great splendid answer! – Bastian Aug 14 '15 at 09:11
  • Since Swift 2: `'#' has been removed from Swift; double up 'param param' to make the argument label the same as the parameter name` – Kof Nov 29 '15 at 07:15
  • Since you're talking about initializing and methods could I please ask you to look at my question. I am trying to call an external function and am pretty sure I am required to implement initialization in order to call it. I've even set a bounty and no one seems up to the challenge. Thank you very much. http://stackoverflow.com/questions/38711226/call-external-function-using-watchkit-force-touch-menuitem – Edison Aug 05 '16 at 23:55
  • When I try to label function parameters in a `typealias` I get a compiler error. Has this changed? – dcow Apr 02 '18 at 23:07
  • Since Swift 3 of course, the first parameter behaves like all the rest, requiring an argument label unless the function or method uses _ (underscore) in place of an external name. – Kal Aug 09 '18 at 03:43
4

The parameter names in the function call are called keyword names, and they are trace their roots back to the Smalltalk language.

Classes and objects are often re-used from somewhere else, or form part of very large complex systems, and will not have active maintenance attention for long periods at a time.

Improving the clarity and legibility of the code is very important in these situations, as code often ends up as the only documentation, when developers are under deadline pressure.

Giving each parameter a descriptive keyword name allows maintainers to quickly see what the purpose of a function call by glancing at the function call, as opposed to delving deeper into the function code itself. It makes the implied meaning of the parameters explicit.

The latest language to adopt keyword names for parameters in function calls is Rust (link) - described as "a systems programming language that runs blazingly fast, prevents segfaults, and guarantees thread safety."

High uptime systems require greater code quality. Keyword names allow development and maintenance teams much more opportunity to avoid and to catch errors from sending the wrong parameter, or calling parameters out of order.

They can be wordy or terse, but Smalltalkers prefer wordy and descriptive to terse and meaningless. They can afford to be, because their IDE will do the bulk of such typing for them.

Euan M
  • 1,126
  • 11
  • 20
  • This is a good explanation. Regarding the language design, this does not justify the added verbosity since we can see the parameter names and the method description with Alt + Left Click. – Cosmin Nov 14 '17 at 13:43
2

since you used calculator.multiply() in the example code I'm assuming this function is a method of the calculator object.

Swift inherits a lot of things from objective-c and this is one of them:

When in objective-c you would do (hypothetically):

[calculator multiply:@9834 factor2:@2321];

the equivalent in Swift is:

calculator.multiply(9834, factor2:2321);
Jiaaro
  • 74,485
  • 42
  • 169
  • 190
  • I plan on accepting this answer. I took a look at the documentation and the example they used there makes a bit more sense than mine did. – 67cherries Jun 04 '14 at 19:38
  • 2
    Quite confusing for people who have not worked with Objective C :) – Kokodoko Jul 28 '14 at 14:55
  • @Kokodoko it is more confusing for people who have worked with objective-c for 5 years :P – Ankit Srivastava Jan 26 '16 at 09:35
  • For all the explanations given on this page, it still doesn't make much sense.... omit the first parameter because the function name already includes that? (it doesn't, not in the multiply example). Also, if Scratch omits the first parameter type because it's so confusing, why didn't they omit all types? Doesn't that make it more confusing? Sorry, just ranting here. – Kokodoko Jan 26 '16 at 11:52
1

Because your "multiply" function is a method, and like Objective-c, the parameters in methods are part of the name.

For example you can do this.

class Calculator {

    func multiply(factor1:Int, factor2:Int) -> Int{
        return factor1 * factor2
    }

    func multiply(factor1:Int, factor2:Int, factor3:Int) -> Int{
        return factor1 * factor2 * factor3
    }

}

Here there are two different methods, with different names, multiply(factor2) and multiply(factor2 factor3).

This rule only apply to methods, if you declare this like a functions outside of a class, then the function call don't require parameter name.

Daniel
  • 783
  • 1
  • 5
  • 16
  • But that still doesn't explain why only the first parameter name can be omitted? Why can't I just add the parameter name for all parameters to keep things readable? This seems to be vintage code from the old Objective C, where the parameter was part of the function name. This caused functions to have very long names. It's quite odd that we still have to understand how Objective C works, if we want to learn Swift. – Kokodoko Jul 28 '14 at 14:53
  • The first parameter is omitted because standard names for methods in cocoa looks like: `func multiplyFactor1(factor1: Int, factor2:Int) {}` So, when you call the method, you omitted the first parameter for avoid repeat it’s name. `myCalculator.multiplyFactor1(2, facto2:2)` Is more readable than. `myCalculator.multiplyFactor1(factor1: 2, facto2:2)` – Daniel Jul 28 '14 at 20:18
0

The reason is historical. This is how it worked in Smalltalk and it survived into its descendants. Squeak, Scratch, Blockly, Objective C and Swift.

The kiddy languages (Squeak, Scratch and Blockly) held to it, because beginning programmers tend to struggle with the arity and parameter order. That was the original reason why Smalltalk did it that way. I do not know why ObjC and Swift decided to adopt the convention, but they did.

Scratch example program

user7610
  • 25,267
  • 15
  • 124
  • 150
  • 1
    Squeak isn't a "kiddy language". It's a fully-featured language, VM, GUI environment and IDE, that people have *used* to implement kid-friendly systems like Scratch, E-Toys and Dr-Geo, the mathematical function visualiser for teaching high-school mathematics.. It also has been used to implement: the Seaside web framework - a framework that does away with all problems to do with people using the 'back' and 'forward' buttons in the browser; DabbleDB; and much more. – Euan M Nov 30 '15 at 01:23
0

A note about passing in a method as an argument that returns no value:

func refresh(obj:Obj, _ method: (Obj)->Void = setValue) {
    method(element)
}
func setValue(obj:Obj){
    obj.value = "someValue"
}
refresh(someObj,setValue)
Sentry.co
  • 5,355
  • 43
  • 38