136

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?

gran_profaci
  • 8,087
  • 15
  • 66
  • 99

10 Answers10

201

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 a let 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 a var 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.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • 7
    "Class instances are passed by reference. Functions are passed by reference" Nope. It is pass-by-value when the parameter is not `inout` regardless of type. Whether something is pass-by-reference is orthogonal to types. – newacct Dec 09 '14 at 01:36
  • 8
    @newacct Well, of course you're right in a strict sense! Strictly, one should say that everything is pass-by-value but that enum instances and struct instances are _value types_ and that class instances and functions are _reference types_. See, for example, https://developer.apple.com/swift/blog/?id=10 - Also see https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ClassesAndStructures.html#//apple_ref/doc/uid/TP40014097-CH13-XID_145 However, I think what I said accords with the general sense of the words mean. – matt Dec 09 '14 at 01:42
  • 8
    Right, and value types / reference types should not be confused with pass-by-value / pass-by-reference, because value types can be passed by value or by reference, and reference types can also be passed by value or by reference. – newacct Dec 09 '14 at 01:45
  • @newacct I still view your comment as somewhat misleading. The average person reading this is here because he is not a Swift expert. Merely stating that everything is passed by value is confusing and does not make clear, for e.g., that it is possible to pass a reference type by reference, thereby pointing to a pointer, which would most likely not be the developer's intent. Matt's original answer is on point. – Adrian Bartholomew Sep 01 '20 at 09:05
  • @AdrianBartholomew: I did not say that everything is passed by value. I said it is pass-by-value without `inout` and pass-by-reference with `inout`. – newacct Sep 01 '20 at 17:35
  • 1
    @newacct I also view these comments as misleading. For example, to say "reference types can also be passed by value or by reference." Semantically, the data inside a reference type is always passed by reference -- period. The reference (pointer) is passed by value, but the semantics for the programmer is that it is always pass by reference, always. Not sure what is meant by suggesting they can also be pass by value. Even if the reference cannot be reassigned, all its data is always a reference. – johnbakers Mar 28 '21 at 13:48
  • @johnbakers: You seem to have a different definition of pass-by-value and pass-by-reference based on "what the data is", which is subjective. Look anywhere on StackOverflow for whether Java has pass-by-value and pass-by-reference, and you will see that under the generally accepted definition, Java only has pass-by-value; whereas you might say that reference types in Java are pass-by-reference. – newacct Apr 04 '21 at 06:04
  • @johnbakers: Here is my objective definition: It's pass-by-value if assignment to a parameter in the called function has no effect on the passed variable in the calling scope; it's pass-by-reference if assignment to a parameter in the called function has the same effect as assignment to the passed variable in the calling scope. Under this definition, Java, Python, C, etc. all have only pass-by-value. But C++, PHP, C#, and Swift all have both pass-by-value and pass-by-reference (with & params in C++ and PHP, `ref` in C#, and `inout` in Swift), and this applies to both value and reference types. – newacct Apr 04 '21 at 06:35
  • @johnbakers: Passing a reference type by reference means that you can assign to the parameter in the called function (to make the reference point to a different object), and it would cause the passed reference variable in the calling scope to also point to the new object. This is something that is not possible in Java or Python, and is not possible in Swift without `inout`, but is possible in Swift with `inout`. That is the difference. – newacct Apr 04 '21 at 06:35
  • @MikeKeskinov Unsure what you mean. You can mutate a reference type object's properties without `inout` in Swift. That is part of how you know it's a reference type. – matt Aug 27 '21 at 16:12
  • 1
    @MikeKeskinov I don't agree. If the parameter is a reference type, the compiler won't tell you anything of the kind. If you have `class Dog {var name = "fido "}`, then you can say `func f(_ dog: Dog) {dog.name = "rover"}`. If that's not what you're seeing, you haven't got a reference type. – matt Aug 28 '21 at 17:55
67

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.

Nate Cook
  • 92,417
  • 32
  • 217
  • 178
  • 5
    For me this is the best answer as it clarified that for example instance properties can be modified inside the function even the parameter being a copy (pass by value) because it points to the same reference. – MrAn3 May 01 '20 at 03:35
50

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 an inout parameter, so it may not fit the traditional definition of pass-by-reference, where you pass the variable directly.

newacct
  • 119,665
  • 29
  • 163
  • 224
  • 3
    This answer, combined with Nate Cook's, was clearer for me (coming from C++) around the fact that even a "reference type" will *not* be modified outside the function scope *unless* you explicitly specify it (by using `inout`) – Gobe Mar 22 '16 at 12:34
  • 16
    `inout` is actually not pass by reference but _copy-in copy-out_ It only guarantees that after function call modified value will be assigned to the original argument. [In-Out Parameters](https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-ID545) – Dalija Prasnikar Apr 13 '17 at 19:41
  • 3
    although it is true that everything is pass by value. Reference types properties can be modified inside the function as the copy references to the same instance. – MrAn3 May 01 '20 at 03:38
17

Here is a small code sample for passing by reference. Avoid doing this, unless you have a strong reason to.

func ComputeSomeValues(_ value1: inout String, _ value2: inout Int){
    value1 = "my great computation 1";
    value2 = 123456;
}

Call it like this

var val1: String = "";
var val2: Int = -1;
ComputeSomeValues(&val1, &val2);
Chris Amelinckx
  • 4,334
  • 2
  • 23
  • 21
  • 1
    Why should you avoid doing this? – Brainless Mar 02 '20 at 15:29
  • 2
    @Brainless because it adds unnecessary complexity to the code. It's best to take parameters in and return a single result out. Having to do this, usually signals poor design. Another way to put it is that hidden side-effects in referenced variables passed in are not transparent to the caller. – Chris Amelinckx Apr 16 '20 at 03:07
  • 4
    This does not pass by reference. `inout` is a copy in, copy out operator. It will first copy in the object, then overwrite the original object after the function returns. While it may seem the same, there are subtle differences. – Hannes Hertach Jun 30 '20 at 12:19
7

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:

Types in Swift fall into one of two categories: first, “value types”, where each instance keeps a unique copy of its data, usually defined as a struct, enum, or tuple. The second, “reference types”, where instances share a single copy of the data, and the type is usually defined as a class.

The Swift blog post continues to explain the differences with examples and suggests when you would use one over the other.

whyceewhite
  • 6,317
  • 7
  • 43
  • 51
  • 3
    This does not answer the question. The question is about pass-by-value vs. pass-by-reference which is completely orthogonal to value types vs. reference types. – Jörg W Mittag Oct 04 '16 at 21:52
3

When you use inout with an infix operator such as += then the &address symbol can be ignored. I guess the compiler assumes pass by reference?

extension Dictionary {
    static func += (left: inout Dictionary, right: Dictionary) {
        for (key, value) in right {
            left[key] = value
        }
    }
}

origDictionary += newDictionaryToAdd

And nicely this dictionary 'add' only does one write to the original reference too, so great for locking!

Jules Burt
  • 115
  • 2
  • 7
2

Classes and structures

One of the most important differences between structures and classes is that structures are always copied when they are passed around in your code, but classes are passed by reference.

Closures

If you assign a closure to a property of a class instance, and the closure captures that instance by referring to the instance or its members, you will create a strong reference cycle between the closure and the instance. Swift uses capture lists to break these strong reference cycles

ARC(Automatic Reference Counting)

Reference counting applies only to instances of classes. Structures and enumerations are value types, not reference types, and are not stored and passed by reference.

mohsen
  • 4,698
  • 1
  • 33
  • 54
1

Classes are passed by references and others are passed by value in default. You can pass by reference by using the inout keyword.

Undo
  • 25,519
  • 37
  • 106
  • 129
  • 2
    This is incorrect. `inout` is a copy in, copy out operator. It will first copy in the object, then overwrite the original object after the function returns. While it may seem the same, there are subtle differences. – Hannes Hertach Jun 30 '20 at 12:20
0

Swift assign, pass and return a value by reference for reference type and by copy for Value Type

[Value vs Reference type]

If compare with Java you can find matches:

  • Java Reference type(all objects)
  • Java primitive type(int, bool...) - Swift extends it using struct
yoAlex5
  • 29,217
  • 8
  • 193
  • 205
-1

struct is a value type so it's always passed as a value. let create struct

    //STEP 1 CREATE PROPERTIES
struct Person{
    var raw : String
    var name: String
    var age: Int
    var profession: String
    // STEP 2 CREATE FUNCTION
    func personInformation(){
        print("\(raw)")
        print("name : \(name)")
        print("age : \(age)")
        print("profession : \(profession)")
    }
}
//allow equal values
B = A then call the function
A.personInformation()
B.personInformation()
print(B.name)

it have the same result when we change the value of 'B' Only Changes Occured in B Because A Value of A is Copied, like B.name = "Zainab" a change occurs in B's name. it is Pass By Value

Pass By Reference Classes Always Use Pass by reference in which only address of occupied memory is copied, when we change similarly as in struct change the value of B , Both A & B is changed because of reference is copied,.