Is a Swift [AnyObject] array variable equivalent to an NSMutableArray? - nsmutablearray

Swift offers fairly painless bridging between Swift native types and there equivalent types in Foundation Classes.
Is an array variable [AnyObject] equivalent in with an NSMutableArray?
var swiftArray: [AnyObject] = ["one", "two", "three"]
var anNSArray: NSMutableArray = ["one", "two", "three"]

Well, no.
There are a number of important differences.
You use the append() method to add objects to a Swift array of AnyObject. You need to use addObject() to add objects to an NSMutableArray:
var swiftArray: [AnyObject] = ["one", "two", "three"]
//swiftArray.addObject["four"] does not work. You have to use `append()`
var anNSArray: NSMutableArray = ["one", "two", "three"]
//anNSArray.append["four"] also does not work. You have to use `addObject()`.
Another major difference: the Swift array is a value type, and the equivalent NSMutableArray is a reference type. So if you pass around a Swift array variable, you actually make a new copy each time it is passed to another variable.
So this code:
var swiftArray: [AnyObject] = ["one", "two", "three"]
var newArray = swiftArray
newArray.append("fortytwo")
print(swiftArray)
/*
Displays "[one, two, three]"
*/
(When you assign swiftArray to a new variable newArray, it creates a new mutable array with the same contents. Adding an item to newArray does not affect the contents of swiftArray.)
Wheras this code:
var anNSArray: NSMutableArray = ["one", "two", "three"]
var newNSArray = anNSArray
newNSArray.addObject("fortytwo")
print(anNSArray)
/*
Displays
(
one,
two,
three,
fortytwo
)
*/
(The NSArray is a reference type, so the assignment
var newNSArray = anNSArray
causes newNSArray to hold a pointer to the existing array, not create a new mutable array. Changing newNSArray changes anNSArray as well, since they are actually the same array.
Another minor difference: The print function invokes the description() method on each object, and Swift arrays and NSArrays format their description string differently. NSArray's description string is rather JSON-looking, whereas the Swift array's description looks more like the code used to generate the array contents in the first place.

Related

When a GString will change its toString representation

I am reading the Groovy closure documentation in https://groovy-lang.org/closures.html#this. Having a question regarding with GString behavior.
Closures in GStrings
The document mentioned the following:
Take the following code:
def x = 1
def gs = "x = ${x}"
assert gs == 'x = 1'
The code behaves as you would expect, but what happens if you add:
x = 2
assert gs == 'x = 2'
You will see that the assert fails! There are two reasons for this:
a GString only evaluates lazily the toString representation of values
the syntax ${x} in a GString does not represent a closure but an expression to $x, evaluated when the GString is created.
In our example, the GString is created with an expression referencing x. When the GString is created, the value of x is 1, so the GString is created with a value of 1. When the assert is triggered, the GString is evaluated and 1 is converted to a String using toString. When we change x to 2, we did change the value of x, but it is a different object, and the GString still references the old one.
A GString will only change its toString representation if the values it references are mutating. If the references change, nothing will happen.
My question is regarding the above-quoted explanation, in the example code, 1 is obviously a value, not a reference type, then if this statement is true, it should update to 2 in the GString right?
The next example listed below I feel also a bit confusing for me (the last part)
why if we mutate Sam to change his name to Lucy, this time the GString is correctly mutated??
I am expecting it won't mutate?? why the behavior is so different in the two examples?
class Person {
String name
String toString() { name }
}
def sam = new Person(name:'Sam')
def lucy = new Person(name:'Lucy')
def p = sam
def gs = "Name: ${p}"
assert gs == 'Name: Sam'
p = Lucy. //if we change p to Lucy
assert gs == 'Name: Sam' // the string still evaluates to Sam because it was the value of p when the GString was created
/* I would expect below to be 'Name: Sam' as well
* if previous example is true. According to the
* explanation mentioned previously.
*/
sam.name = 'Lucy' // so if we mutate Sam to change his name to Lucy
assert gs == 'Name: Lucy' // this time the GString is correctly mutated
Why the comment says 'this time the GString is correctly mutated? In previous comments it just metioned
the string still evaluates to Sam because it was the value of p when the GString was created, the value of p is 'Sam' when the String was created
thus I think it should not change here??
Thanks for kind help.
These two examples explain two different use cases. In the first example, the expression "x = ${x}" creates a GString object that internally stores strings = ['x = '] and values = [1]. You can check internals of this particular GString with println gs.dump():
<org.codehaus.groovy.runtime.GStringImpl#6aa798b strings=[x = , ] values=[1]>
Both objects, a String one in the strings array, and an Integer one in the values array are immutable. (Values are immutable, not arrays.) When the x variable is assigned to a new value, it creates a new object in the memory that is not associated with the 1 stored in the GString.values array. x = 2 is not a mutation. This is new object creation. This is not a Groovy specific thing, this is how Java works. You can try the following pure Java example to see how it works:
List<Integer> list = new ArrayList<>();
Integer number = 2;
list.add(number);
number = 4;
System.out.println(list); // prints: [2]
The use case with a Person class is different. Here you can see how mutation of an object works. When you change sam.name to Lucy, you mutate an internal stage of an object stored in the GString.values array. If you, instead, create a new object and assigned it to sam variable (e.g. sam = new Person(name:"Adam")), it would not affect internals of the existing GString object. The object that was stored internally in the GString did not mutate. The variable sam in this case just refers to a different object in the memory. When you do sam.name = "Lucy", you mutate the object in the memory, thus GString (which uses a reference to the same object) sees this change. It is similar to the following plain Java use case:
List<List<Integer>> list2 = new ArrayList<>();
List<Integer> nested = new ArrayList<>();
nested.add(1);
list2.add(nested);
System.out.println(list2); // prints: [[1]]
nested.add(3);
System.out.println(list2); // prints: [[1,3]]
nested = new ArrayList<>();
System.out.println(list2); // prints: [[1,3]]
You can see that list2 stores the reference to the object in the memory represented by nested variable at the time when nested was added to list2. When you mutated nested list by adding new numbers to it, those changes are reflected in list2, because you mutate an object in the memory that list2 has access to. But when you override nested with a new list, you create a new object, and list2 has no connection with this new object in the memory. You could add integers to this new nested list and list2 won't be affected - it stores a reference to a different object in the memory. (The object that previously could be referred to using nested variable, but this reference was overridden later in the code with a new object.)
GString in this case behaves similarly to the examples with lists I shown you above. If you mutate the state of the interpolated object (e.g. sam.name, or adding integers to nested list), this change is reflected in the GString.toString() that produces a string when the method is called. (The string that is created uses the current state of values stored in the values internal array.) On the other hand, if you override a variable with a new object (e.g. x = 2, sam = new Person(name:"Adam"), or nested = new ArrayList()), it won't change what GString.toString() method produces, because it still uses an object (or objects) that is stored in the memory, and that was previously associated with the variable name you assigned to a new object.
That's almost the whole story, as you can use a Closure for your GString evaluation, so in place of just using the variable:
def gs = "x = ${x}"
You can use a closure that returns the variable:
def gs = "x = ${-> x}"
This means that the value x is evaluated at the time the GString is changed to a String, so this then works (from the original question)
def x = 1
def gs = "x = ${-> x}"
assert gs == 'x = 1'
x = 2
assert gs == 'x = 2'

Swift 4.1: array in dictionary not updated

This strange behavior baffles me. I intend to create a dictionary with a single array field. Then within this array, two extra sub dictionaries are appended. Here is code,
var dictionary = [String: Any]()
var array = [[String: Any]]()
dictionary["array"] = array
var dict1:[String:Any] = ["abc": 123, "def": true]
var dict2:[String:Any] = ["111": 1.2345, "222": "hello"]
array.append(dict1)
array.append(dict2)
Debugger output.
As you can see from the debugger output, the var array is updated successfully (with 2 sub dictionaries appended). But the dictionary["array"] still has 0 value.
It appears the (dictionary["array"]) and (array) are two separate objects
Yes, they are separate. The element dictionary["array"] is an immutable value of type Array<_> because it's added as a value type to the dictionary not a reference type.
If you tried to add dict1 to the array by addressing the element via it's encapsulating dictionary like this:
(dictionary["array"] as! Array).append(dict1)
You would see an error like this:
error: cannot use mutating member on immutable value of type 'Array<_>'
From the Swift Language docs, emphasis added:
A value type is a type whose value is copied when it is assigned to a variable or constant, or when it is passed to a function.
You’ve actually been using value types extensively throughout the previous chapters. In fact, all of the basic types in Swift—integers, floating-point numbers, Booleans, strings, arrays and dictionaries—are value types, and are implemented as structures behind the scenes.

What are the ways to avoid object mutation in Dart-lang?

If we take the following snippet as an example:
main() {
List<int> array = [1, 2, 3, 4];
List<int> newArray = change(array);
print(array); // [99, 2, 3, 4]
print(newArray); // [99, 2, 3, 4]
print(newArray == array); // true
}
change(List<int> array) {
var newArray = array;
newArray[0] = 99;
return newArray;
}
The original array gets mutated. I was expecting that by passing the array (object) to the change function and assigning a new variable to it that I could avoid mutation. I am aware that the built_collection library seems like the main go-to for immutable collections. Is there any native way the core library that would allow for a deep freeze or prevent side effects (operations inside another function)?
You can wrap an array in an UnmodifiableListView from dart:collection and pass this around instead of the array itself. I think this is the most basic buit-in way.
Objects are passed by reference. This is by design: objects are often large data structures and internally making a copy every time an object is passed to a function can be very inefficient. (This is the same approach as that used by other major object oriented languages.)
As a result, array and newArray are two names for the same underlying List in your code.
If you want to explicitly create a new list, just change
var newArray = array;
to:
var newArray = new List.from(array);

Groovy Array of Strings

I know curly brackets are not used to initialize array in Groovy but I have noticed one peculiar thing.
Why groovy doesn't give compiler error when I initialize an array like this.
String emailAddress = "test#gmail.com";
String [] var = {emailAddress};
println var[0];
Output: com.test.examples.GroovyTest$_main_closure1#12e4860e
When I try to declare like this I get error:
String [] var = {"a","b"};
Can anybody explain this?
When you do:
String [] var = {emailAddress};
That creates a Closure that returns a String emailAddress, and then crams that closure into a String array (by calling toString() on it), as that's what you told it to do ;-)
So var equals ['ConsoleScript0$_run_closure1#60fd82c1'] (or similar, depending on where you're running things)
When you do:
String [] var = {"a","b"};
The right-hand side is not a valid Closure, so the script fails to parse.
What you want is:
String[] var = ['a', 'b']
Or:
String[] var = [emailAddress]

Get [String] from NSUserDefaults.standardUserDefaults().dictionaryRepresentation().keys

NSUserDefaults.standardUserDefaults().dictionaryRepresentation().keys returns [NSObject] but I need (and would expect) [String]. Is it just some coffee I'm missing?
dictionaryRepresentation() returns NSDictionary that does not support generic types. You can convert to Swift dictionary:
let dictionary = NSUserDefaults.standardUserDefaults().dictionaryRepresentation() as [String : AnyObject]
let keys = dictionary.keys
That actually returns a LazyBidirectionalCollection<MapCollectionView<Dictionary<Key, Value>, Key>>. You can add .array to get an array instance back, then use map to cast the values to String:
let keys = NSUserDefaults.standardUserDefaults().dictionaryRepresentation().keys.array.map { $0 as String }
println(keys)
// [NSLanguages, NSInterfaceStyle, AppleLanguages]

Resources