Do you need help on a specific subject? Use the contact form (Request a blog entry) on the right hand side.

2015-02-02

Parameter passing

This article will take a look at parameter passing in Swift.

Function parameters are usually stored in a special place in memory, called "the stack". Before the function is called the stack is set up and after the function completes the contents of the stack that was used for the function is discarded.
The compiler can use the stack to pass parameters in two different ways: it either copies the value of a parameter onto the stack, or it copies the address of a parameter into the stack.
When the value is copied ("by value"), the code inside the function has no way to determine the original location of the variable, and hence it is impossible to change this original variable.
When the location of the original variable is copied ("by reference") the code inside the function has full access to the original variable and any changes made will be visible outside the function.

Some types are always passed by value, other are always passed by reference.

The basic types (Int, Double etc) are always passed by value unless the developer takes extra effort to ensure that they are passed by reference.

Class types are always passed by reference. In order to ensure that a function does not change the original object, the developer must create a copy of the original object before calling the function.

Time for some code:

func addFive(value: Int) -> Int {
    return value + 5
}

var a = 5
var b = addFive(a)

println(a)

// prints "5"

This example show passing by value, the original variable "a" is not changed by the code inside the function.

Also note that the following is not possible:

func addFive(value: Int) -> Int {
    value = value + 5  <<< Compiler error
    return value + 5

}

Even though though the value is copied into local memory, the compiler protects against changes to the variable. This makes it clear that the original value is protected against changes. In effect the above is equivalent to:

func addFive(let value: Int) -> Int {
    value = value + 5   <<< compiler error
    return value + 5
}

Here the let keyword makes it explicit that the parameter "value" is not to be messed with.

This also gives us a clue that in order to be able to use "value" as a real variable we can use the var  keyword to make is so:

func addFive(var value: Int) -> Int {
    value = value + 5
    return value + 5
}

var a = 5
var b = addFive(a)
println(a)

// prints "5"

But the original variable is still unaffected by the addition of var. Do note that the value of 'b' is now 15 instead of 10 as in the first code snippet.

If we want to change the original value of 'a', we have to make this explicit through the use of the inout keyword. Adding the inout modifier makes from a call by value a call by reference:

func addFive(inout value: Int) -> Int {
    value = value + 5
    return value + 5
}

var a = 5
var b = addFive(&a)

println(a)

// prints "10"

This time the value of 'a' is changed. But note that the call to the function has also changed: the "&" must be placed in front of the variable. This means that we tell the compiler not to copy the value of 'a', but to use a reference to 'a'. (Called a pointer in C and Objective-C).

Since the code inside the function can now change the original variable, the original variable must be defined as a var, not as a let:

func addFive(inout value: Int) -> Int {
    value = value + 5
    return value + 5
}

let a = 5
var b = addFive(&a<<< compiler error
println(a)

It does not matter if the variable 'a' is never changed, as soon as a variable is passed by reference, it must be defined as a var. Especially on the calls to the lower level API's this can cause some confusion since it can be necessary to pass some immutable data around using pointers. But even though that data itself may be immutable, it must still be defined in a mutable variable. Otherwise we cannot use them in pointer parameters.

Happy Coding...

Did this help?, then please help out a small independent.
If you decide that you want to make a small donation, you can do so by clicking this
link: a cup of coffee ($2) or use the popup on the right hand side for different amounts.
Payments will be processed by PayPal, receiver will be sales at balancingrock dot nl
Bitcoins will be gladly accepted at: 1GacSREBxPy1yskLMc9de2nofNv2SNdwqH

We don't get the world we wish for... we get the world we pay for.

No comments:

Post a Comment