Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Array pass by value by default & thread-safety

Say I have a class which has an Array of object Photo:

class PhotoManager {
  fileprivate var _photos: [Photo] = []

  var photos: [Photo] {
      return _photos
  }
}

I read one article which says the following:

By default in Swift class instances are passed by reference and structs passed by value. Swift’s built-in data types like Array and Dictionary, are implemented as structs.

Meaning that the above getter returns a copy of [Photo] array.

Then, that same article tries to make the getter thread-safe by refactoring the code to:

fileprivate let concurrentPhotoQueue = DispatchQueue(label: "com.raywenderlich.GooglyPuff.photoQueue",
                                                       attributes: .concurrent)
  fileprivate var _photos: [Photo] = []
  var photos: [Photo] {
    var photosCopy: [Photo]!
    concurrentPhotoQueue.sync {
        photosCopy = self._photos
    }
    return photosCopy
  }

The above code explictly make a copy of self._photos in getter.

My questions are:

  1. If by default swift already return an copy (pass by value) like the article said in the first place, why the article copy again to photosCopy to make it thread-safe? I feel myself do not fully understand these two parts mentioned in that article.

  2. Does Swift3 really pass by value by default for Array instance like the article says?

Could someone please clarify it for me? Thanks!

like image 343
Leem.fin Avatar asked Jun 12 '26 04:06

Leem.fin


1 Answers

I'll address your questions in reverse:

  1. Does Swift3 really pass by value by default for Array instance like the article says?

Simple Answer: Yes

But I'm guessing that is not what your concern is when asking "Does Swift3 really pass by value". Swift behaves as if the array is copied in its entirety but behind the scenes it optimises the operation and the whole array is not copied until, and if, it needs to be. Swift uses an optimisation known as copy-on-write (COW).

However for the Swift programmer how the copy is done is not so important as the semantics of the operation - which is that after an assignment/copy the two arrays are independent and mutating one does not effect the other.

  1. If by default swift already return an copy (pass by value) like the article said in the first place, why the article copy again to photosCopy to make it thread-safe? I feel myself do not fully understand these two parts mentioned in that article.

What this code is doing is insuring that the copy is done in a thread-safe way.

An array is not a trivial value, it is implemented as multi-field struct and some of those fields reference other structs and/or objects - this is needed to support an arrays ability to grow in size, etc.

In a multi-threaded system one thread could try to copy the array while another thread is trying to change the array. If these are allowed to happen at the same time then things easily can go wrong, e.g. the array could change while the copy is in progress, resulting in an invalid copy - part old value, part new value.

Swift per se is not thread safe; and in particular it will not prevent an array from being changed while a copy is being performed. The code you have addresses this by using a GCD queue so that during any alteration to the array by one thread all other writes or reads to the array in any other thread are blocked until the alteration is complete.

You might also be concerned that their are multiple copies going on here, self._photos to photoCopy, then photoCopy to the return value. While semantically this is what happens in practice there will probably only be one complex copy (and that will be thread safe) as the Swift system will optimise.

HTH

like image 60
CRD Avatar answered Jun 13 '26 20:06

CRD



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!