Swift: Var parameters

door-3-1415774-m

Swift variables use let and var to indicate whether their values are immutable (cannot be changed after the initial assignment) or mutable (can be updated at will). What many newer Swift developers don’t realize is that closure and function parameters can also be annotated by var and let.

The following function declaration uses let and var keywords to indicate parameter mutability:

func TestFun(let x : String, var y : String) {}

The let keyword is redundant; all parameters default to let, which is called a “constant parameter.” They cannot be changed within the function scope. This compile-time check avoids situations where you mistakenly change the value of a parameter without meaning to. Mandating a var keyword ensures that any value updates for parameters are intentional. For example, the following snippet raises a compile-time error. You cannot assign a new value to ‘let’ value x.

func TestFun(x : String, var y : String) {x = "Hello"} // error!

Here’s an example where assignment does work. You can adjust y to a new value because it is a variable parameter. The example prints out “Hello World” when called with TestFun(“Goodbye”, “Hello”).

func TestFun(x : String, var y : String) {y += " World"; println(y)}

Both x and y are passed by value. The var keyword permits a value to update after the initial call. Even though you tweak y within this function, the y parameter and any variable it was called with do not change outside the function. The parameter’s value is copied and then updated within this scope.

To change the value of an external variable, use Swift’s “inout” call-by-reference copy and write back mechanism (Thanks Nate Cook). Add an inout keyword and pass the address of the variable you intend to mutate by prefixing it with “&”. Here’s an example combining all these concepts.

func AdjustValues(var varParameter : Int, letParameter: Int, inout inoutParameter : Int) { 
    varParameter++ // updates within function scope
//    letParameter++ // compile-time error
    inoutParameter++ // updates within and outside function scope    
    println("\(varParameter) \(letParameter) \(inoutParameter)")
}

var x = 10; var y = 20; var z = 30 // assign
(x, y, z) // (10, 20, 30), check
AdjustValues(x, y, &z) // prints (11, 20, 31)
(x, y, z) // (10, 20, 31) z has now changed

In this example, the call-by-value varParameter (it was called with the value stored in x) increases within the function but does not propagate back to the original variable. The call-by-reference inoutParameter also increases but that change updates the value of z. In Swift you do not have to de-reference the pointer during the assignment.

Now consider the following assignment.

let w = 40

You can pass w to either or both of AdjustValue’s first and second parameters. Immutability outside the function scope does not affect use within the function. However, you cannot pass &w to the AdjustValue’s third parameter. You’ll cause a compiler error because you cannot assign new values to immutable variables in this way.

As always, if there’s anything in this write-up I messed up on, let me know and I’ll fix.

Updated with Nate Cook’s feedback in the comments. Reference (but not call by reference) thread: here.

3 Comments

  • Despite using an &, Swift doesn’t pass inout parameters by reference. Instead it uses a “copy and write back” system, so you aren’t working with a reference to the outer variable when inside a function (which is why you don’t have to dereference the variable like you would in C). There’s a very interesting thread on this subject in the dev forums: https://devforums.apple.com/message/1109791#1109791

    • Thanks Nate! Updated. Take a look see please and let me know if I fixed everything

  • var parameters are deprecated as of Xcode 7.3 Swift 2.2 and will be removed in Swift 3.