Is Swift Pass By Value or Pass By Reference
Asked Answered
M

10

138

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?

Mckenzie answered 8/12, 2014 at 18:6 Comment(3)
"Is the pass by reference the same way as in Objective-C or Java" Neither Objective-C nor Java has pass-by-reference.Basle
Yes. I know that. You don't pass by reference. You pass the reference by value. I assumed that that was known when answering.Mckenzie
Java passes by value, not reference.Abatement
S
204

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.

Sargeant answered 8/12, 2014 at 20:11 Comment(11)
"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.Basle
@Basle 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, developer.apple.com/swift/blog/?id=10 - Also see developer.apple.com/library/ios/documentation/Swift/Conceptual/… However, I think what I said accords with the general sense of the words mean.Sargeant
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.Basle
@Basle 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.Thanh
@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.Basle
@Basle 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.Deidredeific
@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.Basle
@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.Basle
@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.Basle
@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.Sargeant
@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.Sargeant
F
72

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.

Furze answered 8/12, 2014 at 18:19 Comment(1)
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.Parthenon
B
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.

Basle answered 8/12, 2014 at 20:2 Comment(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)Deposit
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 ParametersForging
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.Parthenon
H
18

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);
Hedda answered 14/11, 2017 at 18:0 Comment(3)
Why should you avoid doing this?Consent
@Consent 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.Hedda
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.Dianoia
I
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.

Ibsen answered 4/8, 2015 at 19:36 Comment(1)
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.Inesita
P
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!

Plumate answered 16/4, 2019 at 0:1 Comment(0)
B
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.

Block answered 14/8, 2019 at 5:26 Comment(0)
D
1

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

Decembrist answered 1/11, 2017 at 13:36 Comment(1)
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.Dianoia
E
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
Evetta answered 21/11, 2020 at 14:52 Comment(0)
U
-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,.

Ulphi answered 23/3, 2022 at 11:3 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.