kodeco.com Forums

Reference vs Value Types in Swift: Part 2/2

See reference and value types in action in this tutorial, including an example of how to mix the two effectively and safely.


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/1505-reference-vs-value-types-in-swift-part-2-2

I understand the problem when mixing and matching reference and value types, but one thing i do not understand is why you making a copy each time you access the property and then assign it to the private var. Why not just returning the pivate _billedTo property without copying it ? Does it make any difference ?

This is what i came up with

struct Bill {
let amount: Float
private var _billedTo: Person // 1

// 2
var billedToForRead: Person {
    get {
        return _billedTo.copy() as! Person
    }
}
// 3
var billedToForWrite: Person {
    mutating get {
        return _billedTo
    }
}

init(amount: Float, billedTo: Person) {
    self.amount = amount
    _billedTo = Person(name: billedTo.name, address: billedTo.address)
}

}

What about behavior while Value Types as a function parameter?
Is copy-on-write also used?

Hey @bacid90210, here’s what’s happening.

When accessing billedToForWrite, we want a brand new Person object to edit. This is because our Bill object is a struct, and we expect structs to copy every time we edit one of their properties. When we do _billedTo = Person(name: _billedTo.name, address: _billedTo.address), we are causing Bill to make a copy of itself, and are creating a new reference to Person. Now, the original Bill object and the new copy have two separate underlying Person objects.

If we simply returned the private _billedTo property without copying it, every instance of Bill that was created from an initial Bill object would all reference the same Person object, thus breaking the value semantics expected with Bill.

Let me know if that makes sense, it’s probably easier to visualize with a diagram :]

-E

Hiiii

Since we are declaring both billedToForRead and _billedTo as private so how would the outside code ever get a handle to this variable(i mean the brand new Person Object created from the get on the billedToRead)
I meant let’s say we have var bill = Bill(20.5, personObject1), there is no way we can get bill.billedToForRead or anything else.

I read your article (above) and think, that it is conflicting with some of the things Kyle and Arnold said on WWDC 2016 (see below). Do you think Swift changed here between v2 and v3 or what do you think? Your interpretation of the address changes (and the padding ints for your address struct) suggest, that always an existential container is used for structs (see 2.) and copy-on-write is done automatically (see 3.). But this adds some new questions. Further on you used a playground for your address findings. Does this give the same result as with compiled swift code?

Below please find a question, that I want to post somehow to the people behind swift:

I saw the WWDC 2016 video Understanding Swift Performance as well as some others regarding value types in swift of WWDC2015. I think there are a few ambiguities which make it hard both to decide which weapon to choose and to give proposition how to evolve this implementations to the better (swift-evolution).

Is there a place, where low-level decisions in the language are documented? Is there an adequate place/forum where we can ask questions regarding low-level implementations? It would be great if you add a (moderated) comment section to each of the WWDC videos, so that we can discuss the contents (with transcript-like links) as well as an errata section containing a list of Apple-Approved mistakes/ambiguities in a given video/talk.

So, here come my questions

In the talk Understanding Swift Performance Kyle says, that value types are put stored in the stack and copied. He uses a point and a line which are both copied. Lateron Arnold uses a similar example with protocols. Then the Existential Container is used, which either uses the value buffer (for small values like Point) or allocates some memory on the heap and adds a pointer to this value (e.g. for a Line):

  1. If I have an object (instance of a class) in a variable (or a container like an array) of a protocol type, will it be stored into an Existential Container, too? Or are reference types always stored as a reference (storing it in an Existential Container makes more sense to me).
  2. If I use a variable of the concrete type (although it implements a protocol), will it always be copied (no matter its size) or does the compiler choose an existential container if it is greater than some given size (or perhaps even always, because it gives a good tradeoff?)
  3. Then Arnold says that four existential containers pointing to the same value (greater than the value buffer) use 4 heap allocations. He proposes copy-on-write (using a local storage class), but does he mean this should be implemented by hand or is this an optimization that the swift compiler does on its own? The issue here is, that the switch between “swift subscript” for showing an abstraction of internals and real swift code that one should write is sometimes not clear. Doing this by hand has some clear disadvantages as this would add a reference to each usage of Line (and reference counting) even in the first examples of Kyle. Doing this as a compiler optimization would allow to use a struct in different scenarios and always the best tradeoff is used. Otherwise, I would perhaps even need to create two different types for different situations and choose it wisely. This would add a big burden on the developer.
  4. If Arnold really means manually (see 3.) and reference types are not stored in existential containers (see 1.) the slides are wrong, because there a existential container is still used and the instance on the heap is named Line instead of Line._storage. So what is the case?
  5. The implementations of String and Array seem to follow the copy-on-write strategy “manually”, but I think they do that because this behavior is wanted even if the values would be copied automatically (if this is true, the answer for 3. would be manually). Or am I wrong here?
  6. Is the Value-Witness-Table a (kind of) dictionary for all values of a given value type (bigger than the value buffer), so that you do not store any value twice on the heap, but share the reference? If this is the case the answer of 3. should be automatically. But then again, the “manual” implementation of String and Array (see 4.) make no sense anymore, does it? Or are Array and String implemented only on the lower-level and the copy-on-write implementation is not visible in their Swift implementation?
  7. If you want to have a reference-type (like NSData) with value semantics, then I need to implement my own copy-on-write of course, but if I want to have it only on the swift-value-type level the compiler should be able to do it all by itself, shouldn’t it?

It would be great, if someone could give me the answers to these questions :).

All the best
Johannes

So I asked at the swift-dev list and I’m sorry to say that, but this post about Swift value types is wrong in some points. Value types are implemented much less magically than described here (although what you write would be nice). I will write a post on my blog soon, regarding this topic and will inform you.

Hey @juangamnik, Thanks for the super thorough comments. I have not had a chance to go through this article with Swift 3. It definitely worked in Swift 2 and was verifiable. This article won’t be updated until we get closer to the official release of Swift 3, and at that time I’ll definitely look for any incorrect points. Any notes you find while writing your blog post will be helpful :] -Eric

Sorry to say that, but the interpretation of the results (with pointer addresses) is wrong (for any Swift version). Your pointer address points to the indirect storage of the String not of the Address. I was confused, because your findings were contradictory to the mentioned Swift talk on WWDC and I asked the presenter Arnold Schwaighofer and he gave me some insights how it is implemented in Swift and there is no automatic indirect storage with unique value pool or the like. I will send you a link to my blog post as soon as it is ready.

Hi,

Did you eventually get to finishing that blog post? I’m very interested in that as well, and the “magic” that this post is about was weird for me too…

Thanks.

I’m just back from holidays and will write the article ASAP. As we germans say: “It burns under my nails” :slight_smile:. I’ll post here then.

Thanks Juan,

In general, I guess your experience is that swift structs copy (and do not share memory anyway, magically), and that if you want copy-on-write, you need to implement it yourself, via isUniquelyReferencedNonObjC, like Apple does on Swift Arrays for example. right?

Dear bartzy,

In essence you are right. But my blog post will shed some light on value semantics (and why they are cool), too. Further on, it will discuss existential containers and some more details as presented on WWDC this year.

All the best
Jonny

Hi Jonny,

Did you eventually publish that post?

Thanks,
Bar.

This tutorial is more than six months old so questions are no longer supported at the moment for it. We will update it as soon as possible. Thank you! :]