I was reading the apple doc when I fell upon this piece of syntax :
struct Point {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
x += deltaX
y += deltaY
}
}
var somePoint = Point(x: 1.0, y: 1.0)
somePoint.moveBy(x: 2.0, y: 3.0)
print("The point is now at (\(somePoint.x), \(somePoint.y))")
// Prints "The point is now at (3.0, 4.0)"
Could someone explain why moveBy(x deltaX: Double, y deltaY: Double) has double labels on the arguments ?
Short answer: first argument label is for external caller, second one for local in-method use.
func moveBy(x deltaX: Double, y deltaY: Double) when calling looks following: moveBy(x: 1, y: 1), but inside the method deltaX and deltaY labels are used.
This naming style is not necessary, you can declare the method func moveBy(x: Double, y: Double) so x and y will be used inside the method.
To support legacy style, so from caller scope your method looks like moveBy(1, 1), you should place _ as first argument label: func moveBy(_ deltaX: Double, _ deltaY: Double). Such declarations are used in CocoaTouch to support legacy obj-c interface (ex. func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool).
The first label is Argument Labels and the second label is Parameter Names.
From Apple Document:
Each function parameter has both an argument label and a parameter
name. The argument label is used when calling the function; each
argument is written in the function call with its argument label
before it. The parameter name is used in the implementation of the
function. By default, parameters use their parameter name as their
argument label.
Usage:
func foo(with hoge: Int) {
return hoge * 2
}
let A = foo(with: 2) // A = 4;
Look closely to the Apple documentation.It is connected with Parameter Names.
You can override the default behavior for argument labels with one of
the following forms:
argument label parameter name: parameter type
_ parameter name: parameter type
Related
I am somewhat familiar with storing and passing around functions in Swift, however I have a few specific questions on the behavior of the language in this regard.
Say we have a variable function MathOperation:
var mathOperation: (Double, Double) -> Double
Now suppose we are setting this to the function Subtract:
func subtract (minuend: Double, subtrahend: Double) -> Double {
return minuend - subtrahend
}
mathOperation = subtract
We should then be able to call subtract with
let result = mathOperation(3, 4.222)
But what if we want to pass in a function that has more parameters, or differently ordered parameters than the declaration of mathOperation calls for? For instance:
func divide (dividend: Double, divisor: Double, roundToInt: Bool = false) -> Double { ... }
How can I set mathOperation to divide in such a manner that roundToInt is ignored?
Also, is it possible to re-order the arguments? Say we have an exponentiation function in a library where it cannot be modified:
func exponentiate (power: Double, base: Double) -> Double { ... }
It is unusual to have the power before the base, and let's say that where mathOperation is used, we need to call it as though it were declared with (base: Double, power: Double).
Is there a way to set mathOperation to exponentiate so that the parameters are reversed when it is called?
One final question. Let us say we have an interpolation function that we want to set mathOperation to:
func interpolate (start: Double, end: Double, by: Double, nonlinearity: (Double) -> Double) -> Double { ... }
Is there a way to set mathOperation to interpolate so that
mathOperation (a, b)
results in
interpolate (start: a, end: b, by: 0.5, nonlinearity: { $0 })
If any of these are possible, it would be ideal if someone could direct me to the official documentation where this is explained.
For your interpolate case (the other cases follow) just define the following:
mathOperation = { interpolate (start: $0, end: $1, by: 0.5, nonlinearity: { $0 })}
Essentially you wrap interpolate in a closure where some of the arguments are fixed, such as by to 0.5 in this example. (This is referred to as 'partial application')
You can also generalize this with something like the following:
func interpolateToMathOperation (by: Double, nonlinearity: #escaping (Double) -> Double) -> (Double, Double) -> Double {
return { interpolate (start: $0, end: $1, by: by, nonlinearity: nonlinearity)}
}
The above returns a mathOperation for interpolate given the default by and nonlinearity arguments.
In action:
// Just add - only an example
1> func interpolate (start: Double, end: Double, by: Double, nonlinearity: (Double) -> Double) -> Double { return start + end }
6> func interpolateToMathOperation (by: Double, nonlinearity: #escaping (Double) -> Double) -> (Double, Double) -> Double {
7. return { interpolate (start: $0, end: $1, by: by, nonlinearity: nonlinearity)}
8. }
9> var mathOperation = interpolateToMathOperation (by: 0.25, nonlinearity: { $0 })
mathOperation: (Double, Double) -> Double = 0x00000001005ea670 $__lldb_expr15`partial apply forwarder for __lldb_expr_14.(interpolateToMathOperation (by : Swift.Double, nonlinearity : (Swift.Double) -> Swift.Double) -> (Swift.Double, Swift.Double) -> Swift.Double).(closure #1) at repl14.swift
10> mathOperation(1,2)
$R1: Double = 3
I'm doing a lot of positioning and animation stuff in literals, and they're taking up a lot of space and becoming unreadable because of the verbosity.
What I'd like to do is turn this
var xy = CGPoint(x: 100, y: 100)
Into this:
var xy = •(100, 100)
Similarly, I'd like to go from:
CGVector(dx: 200, dy: 200)
to something like this:
`(200, 200)
But I don't know how a macro-like shorthand or something like this would be done, or even if it could be done. Any pointers (puntendered) would be better than where I'm at.
I get that this is probably, for most people, less readable.
Due to the context I always know what these are. I don't need the parameter labels or function name to understand what I'm doing. And this is private animation and motion testing, there's no need for anyone else to ever understand what's going on.
extension CGPoint {
init(_ x: CGFloat, _ y: CGFloat) {
self.init(x: x, y: y)
}
}
extension CGVector {
init(_ dx: CGFloat, _ dy: CGFloat) {
self.init(dx: dx, dy: dy)
}
}
typealias P = CGPoint
typealias V = CGVector
let p = P(10, 10)
let v = V(10, 10)
But no idea about the • and ` part - I replaced them with P and V :)
For this type of thing you would likely use a typealias but I don't think you will be able to create types with names as operators or symbols.
See below, I created a typeAlias of CGP for CGPoint, you could simply just alias it to Point if you like.
Here is some information from the docs
A type alias declaration introduces a named alias of an existing type into your program. Type alias declarations are declared using the typealias keyword and have the following form:
typealias name = existing type
After a type alias is declared, the aliased name can be used instead of the existing type everywhere in your program. The existing type can be a named type or a compound type. Type aliases do not create new types; they simply allow a name to refer to an existing type.
EDIT
Two simple method of excluding the parameter names:
func cp(_ x: Int, _ y: Int) -> CGPoint {
return CGPoint(x: x, y: y)
}
let point = cp(0,2)
extension CGPoint {
init(_ x: Int, _ y: Int) {
self.init(x: x, y: y)
}
}
typealias CGP = CGPoint
let point2 = CGP(1,1)
The first method just creates a helper function which returns a CGPoint using it's designed intialiser. The second option is the better way of doing it, you extend CGPoint and add an intializer that marks the params as non-named params (by using the _ instead of the external name)
You can't use special characters as the compiler would not be able to differentiate between function names and operators like '*'.
Using typealias
using a typealias would allow you to shorten the function name but not omit the parameter names like you outlined in your question.
typealias p = CGPoint
//example
let p1 = p(x: 60, y: 60)
Using anonymous parameters
func p(_ x: CGFloat, _ y: CGFloat) -> CGPoint {
return CGPoint(x: x,y: y)
}
//example
let p1 = p(60, 60) //no parameter names
I too like to get rid of the parameter labels, but I don't advise reducing things to any briefer shorthand. I paste this code into the start of all my app projects:
extension CGRect {
init(_ x:CGFloat, _ y:CGFloat, _ w:CGFloat, _ h:CGFloat) {
self.init(x:x, y:y, width:w, height:h)
}
}
extension CGSize {
init(_ width:CGFloat, _ height:CGFloat) {
self.init(width:width, height:height)
}
}
extension CGPoint {
init(_ x:CGFloat, _ y:CGFloat) {
self.init(x:x, y:y)
}
}
extension CGVector {
init (_ dx:CGFloat, _ dy:CGFloat) {
self.init(dx:dx, dy:dy)
}
}
That allows me to say things like CGPoint(1,4), and that's good enough, in my opinion.
I'm reading through the Swift 2.2 man and trying to understand a function in the mutating fun section here is the code
struct TestPoint {
var x = 0.0, y = 0.0
mutating func moveByX(deltaX: Double, y deltaY: Double) {
self = TestPoint(x: x + deltaX, y: y + deltaY)
}
}
var somePoint = TestPoint(x: 1.0, y: 1.0)
somePoint.moveByX(2.0, y: 3.0)
print("The point is now at (\(somePoint.x), \(somePoint.y))")
The part I'm having trouble is with the func moveByX syntax. y deltaY for example how is this allowed? y is the declared variable in the struct but where does the deltaY bit come in ?
Only two values are passed in somePoint.moveBy
Is the value passed to both y and deltaY ?
thanks for any help
Internal and external parameter names
Let's look at the function signature of moveByX(...):
mutating func moveByX(deltaX: Double, y deltaY: Double)
/* | / ^^^^^^- internal name
| external name
internal name */
In Swift 2.2, by default the first function parameter as no external name (_), which means that the function moveByX(...) is called as:
someTestPointInstance.moveByX(someXvalue, y: someYvalue)
/* | \
no external name external name */
This means that the y that you see in the signature of moveByX(...) is just an external parameter name, one that no longer has any use when we've entered the body of the function (where the internal parameter name, deltaY is used). So the second argument passed to moveByX(...), to the external parameter name y, will be referred (in this case, copied to) deltaY in the actual function body.
Finally note that the x and y properties used in the body of the function
self = TestPoint(x: x + deltaX, y: y + deltaY)
are the member properties x and y as defined in the definition of the SomePoint struct.
Is the above still valid for Swift 3.0?
As somewhat covered above: if we don't supply explicit external parameter names for function parameters in Swift 2.2, then the following rules apply:
By default, the first function parameter will have no external parameter name (as seen above, _).
By default, all the following function parameters (second, third, and so on) will have the same external parameter name as internal parameter name. So in case we would've written the function signature of moveByX(...) as
mutating func moveByX(deltaX: Double, deltaY: Double)
then the external parameter name of the second parameter would've been deltaY, and we would've called the function as
someTestPointInstance.moveByX(someXvalue, deltaY: someYvalue)
In Swift 3.0 all parameter names follows the second rule above, namely; if no external parameter name has been supplied, then the internal parameter name will be used as external parameter name for all parameters.
That means the example above would have to be modified into something along the lines
struct TestPoint {
var x = 0.0, y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
self = TestPoint(x: x + deltaX, y: y + deltaY)
}
}
// called as
someTestPointInstance.moveBy(x: someXvalue, y: someYvalue)
Read the chapter "Function Parameter Names".
Basically, in moveByX, "y" is an external parameter name for "deltaY" and it's used to label "deltaY".
In Swift, if you have two variables :
var a:Int = 2
var b:Double = 3.4
And if you try to do :
var c = a+b
It will trigger an compile-time error, because you cannot add two variables that aren't of the same type.
But still, you could do :
var c = b+2
It would work because 2, by itself, doesn't have any type, so even if it isn't a decimal number (I mean, I din't wrote 2.0), it stills work.
Now, here is my question, why doesn't the same principle applies when I do :
acos(1)
But it works when I do :
acos(1.0)
I see that acos() can take Double, Float, and CGFloat as an argument, but shouldn't Xcode infer that 1 is in fact a Double ?
This is an interesting question. Note that if I define my own function myAcos that takes a Double, I can call it with myAcos(1):
func myAcos(d: Double) -> Double {
return 0.0
}
let a = myAcos(1) // This works
Now, if I add a second myAcos that takes and returns a Float:
func myAcos(f: Float) -> Float {
return 0.0
}
The call to myAcos(1) now give the error: error: ambiguous use of 'myAcos'
Then, I add a third function myAcos that takes and returns a CGFloat:
func myAcos(c: CGFloat) -> CGFloat {
return 0.0
}
The call to myAcos(1) then gives the error: error: could not find an overload for 'myAcos' that accepts the supplied arguments
If I then add a fourth myAcos function that takes and returns an Int, then myAcos(1) works:
func myAcos(i: Int) -> Int {
return 0
}
myAcos(1) // This works, again
So, the answer to your question appears to be that you can't call acos(1) because Swift can't figure out which version of acos you are attempting to call.
The language spec defines (see Literals in Language Reference) that 1 is an Integer literal and Swift doesn't allow implicit type conversion.
This is for good reasons because it makes expressions like
3 / 2
more unambiguous.
I keep getting the error "extra argument in call" for repeatedValue in the init function. Why?
class Point<T> {
/* n dimensional point
multiline comments ...
*/
let point : [T]
init(dimensions: Int, rValue: Float = 0.0){
self.point = [T](count: dimensions, repeatedValue:rValue)
}
}
The definition for init with repeatedValue is
Array<T> init(count: Int, repeatedValue: T)
Your rValue must be of type T
If you need the default value your T has also to be a FloatLiteralConvertible,
this:
Array<T> init(count: Int, repeatedValue: T)
won't do it. This however will work and makes more sense since you don`t want points made out of for example "Cats" i guess...
Solution:
class Point<T:FloatLiteralConvertible> {
/* n dimensional point
multiline comments ...
*/
let point : [T]
init(dimensions: Int, rValue: T = 0.0 ){
self.point = [T](count: dimensions, repeatedValue:rValue)
}
}
var pd = Point<Double>(dimensions: 10, rValue: 1.0)
var pf = Point<Float>(dimensions: 10, rValue: 1.0)
dump(pd.point)
dump(pf.point)