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?
Parameters are essential to functions, because otherwise you can't give the function-machine an input.
Defining a Function Without Parameters When we call this function, it will print the current date. Note that, this output can be different for you. The output will be the date in which you call the function.
The parameters, in a function call, are the function's arguments. JavaScript arguments are passed by value: The function only gets to know the values, not the argument's locations. If a function changes an argument's value, it does not change the parameter's original value.
To pass function as parameter to another function in Swift, declare the parameter to receive a function with specific parameters and return type. The syntax to declare the parameter that can accept a function is same as that of declaring a variable to store a function.
Update for Swift 2.0: Now functions behave identically to methods, and for both, by default:
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.
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)
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
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With