I'm really new to Swift and I just read that classes are passed by reference and arrays/strings etc. are copied.
Is the pass by reference the same way as in Objective-C or Java wherein you actually pass "a" reference or is it proper pass by reference?
Classes are passed by references and others are passed by value in default. You can pass by reference by using the
inout
keyword.Here is a small code sample for passing by reference. Avoid doing this, unless you have a strong reason to.
Call it like this
It is always pass-by-value when the parameter is not
inout
.It is always pass-by-reference if the parameter is
inout
. However, this is somewhat complicated by the fact you need to explicitly use the&
operator on the argument when passing to aninout
parameter, so it may not fit the traditional definition of pass-by-reference, where you pass the variable directly.Types of Things in Swift
The rule is:
Class instances are reference types (i.e. your reference to a class instance is effectively a pointer)
Functions are reference types
Everything else is a value type; "everything else" simply means instances of structs and instances of enums, because that's all there is in Swift. Arrays and strings are struct instances, for example. You can pass a reference to one of those things (as a function argument) by using
inout
and taking the address, as newacct has pointed out. But the type is itself a value type.What Reference Types Mean For You
A reference type object is special in practice because:
Mere assignment or passing to function can yield multiple references to the same object
The object itself is mutable even if the reference to it is a constant (
let
, either explicit or implied).A mutation to the object affects that object as seen by all references to it.
Those can be dangers, so keep an eye out. On the other hand, passing a reference type is clearly efficient because only a pointer is copied and passed, which is trivial.
What Value Types Mean For You
Clearly, passing a value type is "safer", and
let
means what it says: you can't mutate a struct instance or enum instance through alet
reference. On the other hand, that safety is achieved by making a separate copy of the value, isn't it? Doesn't that make passing a value type potentially expensive?Well, yes and no. It isn't as bad as you might think. As Nate Cook has said, passing a value type does not necessarily imply copying, because
let
(explicit or implied) guarantees immutability so there's no need to copy anything. And even passing into avar
reference doesn't mean that things will be copied, only that they can be if necessary (because there's a mutation). The docs specifically advise you not to get your knickers in a twist.The Apple Swift Developer blog has a post called Value and Reference Types that provides a clear and detailed discussion on this very topic.
To quote:
The Swift blog post continues to explain the differences with examples and suggests when you would use one over the other.
Everything in Swift is passed by "copy" by default, so when you pass a value-type you get a copy of the value, and when you pass a reference type you get a copy of the reference, with all that that implies. (That is, the copy of the reference still points to the same instance as the original reference.)
I use scare quotes around the "copy" above because Swift does a lot of optimization; wherever possible, it doesn't copy until there's a mutation or the possibility of mutation. Since parameters are immutable by default, this means that most of the time no copy actually happens.