Swift: Fun with Parameter names!

Swift parameters generalize functions. They creates flexible code whose outcome is controlled at run-time by the values they are passed. Here’s a function that builds a UIBezierPath based-wedge. It constructs this from a radius and angle.

Original Function

func BezierWedge(radius : Double, angle : Double) -> UIBezierPath
    let path = UIBezierPath()
    path.addLineToPoint(CGPointMake(radius, 0))
    path.addArcWithCenter(CGPointZero, radius: Double(radius), 
        startAngle: 0, endAngle: M_PI * 2 - angle, 
        clockwise: false)
    return path

You call this function with two parameters, both typed as double.

Call #1

BezierWedge(30, 3 * M_PI_4)

Using this approach is practical and simple. As you start to type, Xcode auto-completes the method for you. You replace the placeholders with the two arguments as in Call #1.

The drawback is readability. The great advantage of Objective-C selector in-line argument names lies in the self-documentation it provides. In the original function, you cannot use those labels directly.

Call #2

BezierWedge(radius: 30, angle: 3 * M_PI_4)

If you try to compile the code in Call #2, Xcode complains of “extraneous argument labels”. That’s because internal parameter names can only be used within the function that declares them. If you want to add explicit parameter names you need a different approach.

To enable labels, also called “external parameter names”, add a pound sign before each argument. Here’s an updated function declaration, one that mandates the radius: and angle: labels. Once updated, the compiler accepts call #2 and complains about call #1 (it says “Missing argument labels in call”). If you want, you can alsos

Updated Function Declaration

func BezierWedge(#radius : Double, #angle : Double) -> UIBezierPath {...}

You can mix and match required and positional parameter names if desired. This next declaration requires the angle label but not the radius one.

Mix and Match Declaration

func BezierWedge(radius : Double, #angle : Double) -> UIBezierPath {...}

Call #3

BezierWedge(30, angle: 3 * M_PI_4)

The external parameter name does not have to match the internal one. You can explicitly specify both, as in the following example.

Declaration with distinct external and internal parameter names

func BezierWedge(#radius : Double, acrossAngle angle : Double) -> UIBezierPath {...}

Call #4

BezierWedge(radius: 30, acrossAngle: 3 * M_PI_4)

As you see, the external parameter name is always first, and the internal parameter name second. In this example,”acrossAngle” is the external name. The internal name is “angle”. This variation changes the call (Call #4) but not the internal implementation, which remains as it was in the original function. Using external parameter names helps you add more semantic meaning to the call, differentiating between how the parameter will be used and the name of the parameter’s value.

Swift permits you to assign default values to any function parameter. When added, you can omit a parameter when calling the function. For example, the following function declaration enables you to either or both parameters and make calls #5 – #8. Adding default values implicitly triggers external parameter labels.

Declaring default values:

func BezierWedge(radius : Double = 30, angle : Double = M_PI) -> UIBezierPath {...}

Calls #5, #6, #7, #8

BezierWedge(angle:M_PI_4, radius:40) // Flipped!

To use positional (vs labeled) arguments with default values, use underscores. Underscores are the “don’t care” placeholders of Swift. Here, they say “skip external parameter names”. Calls 9-11 offer examples for the following function declaration.

Using underscores with functions:

func BezierWedge(_ radius: Double = 30, _ angle: Double = M_PI) -> UIBezierPath {...}

Calls #9-#11

BezierWedge(50, M_PI_4)

 Update: Cédric Bozzi pinged me about whether the parameters could be re-ordered. I know they can be in the case with default values but most other experiments raised errors.

Screen Shot 2014-06-16 at 7.44.24 AM

One Comment