5

I wrote the Objective-C code first

NSMutableString *aStrValue = [NSMutableString stringWithString:@"Hello"];
NSMutableDictionary *aMutDict = [NSMutableDictionary dictionary];
[aMutDict setObject:aStrValue forKey:@"name"];

NSLog(@"Before %@",aMutDict);
[aStrValue appendString:@" World"];
NSLog(@"After %@",aMutDict);

I got the output as follows

2015-09-17 14:27:21.052 ShareIt[4946:129853] Before {
    name = Hello;
}
2015-09-17 14:27:21.057 ShareIt[4946:129853] After {
    name = "Hello World";
}

Means when I append a string to a Mutable string which is actually referred into a MutableDictionary, the change is getting reflected in Dictionary too..

But then I tried something same in Swift

var stringValue:String?
stringValue = "Hello"

var dict:Dictionary = ["name":stringValue!]
println(dict)
stringValue! += " World"
stringValue!.extend(" !!!!")
println(dict)

I seen the output in playground like this enter image description here

My Questions are

  • Why the value that changed is not reflecting in a data structure like Dictionary.
  • Does in Swift adding any key value really keeps the value or its reference, if it's keeping the reference like objective-C then here what is my mistake?
Mrug
  • 4,963
  • 2
  • 31
  • 53

3 Answers3

4

Reference type

The different behaviours depends on the fact that in the Objective-C code you use NSMutableString that is a class. This means that aMutDict and aStrValue are references to the same object of type NSMutableString. So the changes you apply using aStrValue are visibile by aMutDict.

Value type

On the other hand in Swift you are using the String struct. This is a value type. This means that when you copy the value from one variable to another, the change you do using the first variable are not visible to the second one.

The following example clearly describes the value type behaviour:

var word0 = "Hello"
var word1 = word0

word0 += " world" // this will NOT impact word1

word0 // "Hello world"
word1 // "Hello"

Hope this helps.

Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148
  • 3
    @user2864740: How? appzYourLife's answer is absolutely correct. – DarkDust Sep 17 '15 at 09:15
  • 2
    @user2864740: Both examples (`Objective-C` and `Swift`) are in the **mutable context**. Infact the OP uses `NSMutableString`, `NSMutableDictionary`, `var String` and `var Dictionary` (all `mutables`). The real difference here is that `NSMutableString` is an object (**reference type**) while `String` is a struct (**value type**). So here we are talking about `reference types` and `value types`, **not mutability**. – Luca Angeletti Sep 17 '15 at 09:30
  • @appzYourLife The `+` operator does not mutate the String but rather returns a new value; in any context. The resulting assignment (to a variable) and following `extend` are thus independent of any value stored in the dictionary, in any context. To make it a question of value type vs reference type (and not just immutability of operations) would require an actual operation that attempted to modify the original object, and then explain the behavior therein. – user2864740 Sep 17 '15 at 09:56
  • 1
    One more thing – in ObjC, only `NSMutableString` is passed as reference type, on the other hand `NSString` behaves like a value type. That's because of thing known as [string interning](https://en.wikipedia.org/wiki/String_interning) – Matt told me [here](http://nshipster.com/equality/) – Pavel Smejkal Sep 17 '15 at 09:58
  • @PavelSmejkal: you are right. I replaced `NSString` with `NSMutableString` in the first paragraph of my answer. Thank you! – Luca Angeletti Sep 17 '15 at 10:01
  • @user2864740: I am afraid you are wrong. Look at this line in the OP `stringValue! += " World"`. This instruction obviously **modify** the content of `stringValue`. But since `stringValue` is a `value type` the change is not reflected inside the `Dictionary` because **it has a copy**. So we are talking about `reference type` and `value type`. **Not mutabilty/immutability**. – Luca Angeletti Sep 17 '15 at 11:35
  • @appzYourLife `+=` does not modify the original string any more than it modifies an integer. It is merely a compound assignment - [as shown in this code](http://swiftstub.com/254516565/?v=gm). *The 'example of the difference' code shown would have worked the way it does on any operations that did not mutate the original type.* – user2864740 Sep 17 '15 at 18:07
  • @appzYourLife Personally I think the Swift documentation is hogwash as written with too sloppy a mixture of mutability/immutability of *objects* (values) and *bindings* (names which represent values) - see http://stackoverflow.com/questions/24221786/are-swift-mutable-strings-really-mutable-or-are-they-just-like-java-strings – user2864740 Sep 17 '15 at 18:16
  • @appzYourLife That being said, if you can show me any example of *actually* mutating a *string value* as opposed to a *binding*, I would be most interested to see it. – user2864740 Sep 17 '15 at 18:18
  • @user2864740 Very good point I understand what you mean but please let's examine togheter some facts. **1)** The Swift `copy on write` technique does not seem applied looking at the result of `unsafeAddressOf` here http://swiftstub.com/324640401/?v=gm Why? **2)** `unsafeAddressOf` accepts as param `AnyObject`, why does `String` (a `struct`) conform to AnyObject? http://stackoverflow.com/questions/26403542/swift-string-doesnt-conform-to-anyobject **3)** With mechanisms of abstractions like `copy on write` (and maybe others) is it safe and reliable for us considering memory addresses of structs? – Luca Angeletti Sep 17 '15 at 19:26
  • @user2864740: I mean, when I write `word0 += " world"` I can consider `word0` a `struct`, `mutable` and `value type`. At low level I understand that `word0` is still a pointer and that the next line `word0` does point to a different memory location but these are details we should not care about here (IMHO). As I don't care that `let word0 = "hello"; let word1 = word` actually creates 2 `pointers` to the **same memory location**. Because conceptually `word0` and `word1` are simply 2 independent value types. And if I treat them like that Swift will take care of the rest. – Luca Angeletti Sep 17 '15 at 19:35
  • @user2864740: But seriously, I see your point. I could be wrong and I would like to know what you think about. – Luca Angeletti Sep 17 '15 at 19:38
  • 1
    @user2864740: I asked a specific question about this: http://stackoverflow.com/questions/32638879/swift-strings-and-memory-addresses – Luca Angeletti Sep 17 '15 at 20:08
  • 1
    @appzYourLife Ahh, [me too](http://stackoverflow.com/questions/32637688/is-it-possible-to-mutate-a-string-in-swift-such-that-it-can-be-proven-to-modify) (from a different angle). Very interesting learning new stuff - ie. I thought the address would have been pinned without an in-between operations. – user2864740 Sep 17 '15 at 20:52
  • Yes, thanks to this "thread" I discovered a few new thing today :D – Luca Angeletti Sep 17 '15 at 21:00
4

Strings in Swift (copy by value) are completely different than string in Objective C (copy by reference).

From Apple' Swift documentation:

Strings Are Value Types

Swift’s String type is a value type. If you create a new String value, that String value is copied when it is passed to a function or method, or when it is assigned to a constant or variable. In each case, a new copy of the existing String value is created, and the new copy is passed or assigned, not the original version. Value types are described in Structures and Enumerations Are Value Types.

Swift’s copy-by-default String behavior ensures that when a function or method passes you a String value, it is clear that you own that exact String value, regardless of where it came from. You can be confident that the string you are passed will not be modified unless you modify it yourself.

Behind the scenes, Swift’s compiler optimizes string usage so that actual copying takes place only when absolutely necessary. This means you always get great performance when working with strings as value types.

Abhinav
  • 37,684
  • 43
  • 191
  • 309
2

In swift, String is a Struct. Structs are not reference types in Swift, thus it's copied when you setting it to a dictionary.

Pavel Smejkal
  • 3,600
  • 6
  • 27
  • 45
  • 2
    @user2864740: [Strings in Swift are structs](http://stackoverflow.com/questions/25112081/is-string-type-a-class-or-a-struct-or-something-else), _not_ reference types. – DarkDust Sep 17 '15 at 09:16
  • 2
    @user2864740: Then please provide an answer. So far you're only disagreeing with people and don't provide any useful data. – DarkDust Sep 17 '15 at 09:17
  • 2
    @user2864740 This answer says what the problem is in couple words and it's right, thanks – Pavel Smejkal Sep 17 '15 at 09:18