assignment of two Scala class instances - scala

class Counter {
var counter: Int = 0
def increaseCounter(): Unit =
counter = counter + 1
}
var counter1 = new Counter
var counter2 = new Counter
counter1 = counter2
counter1.increaseCounter()
counter2.counter // => 1
I do not really understand why the counter of counter2 is changed even though I only changed the counter of counter1. Are Scala class instances just pointers and in this case counter1 and counter2 are pointing to the same object?

Scala variables are just pointers, so this:
counter1 = counter2
makes both counter1 and counter2 point to the same instance.
This kind of hidden dependency is why you should avoid var as much as possible and always create new objects rather than modifying existing objects.

Yes. Just like in Java. This you did is a shallow copy. If you want to assign the value of one be copied to the other you need a deep copy. You need
counter1.counter = counter2.counter

Related

Does the String argument to PageStorageKey really matter?

When Supplying a PageStorageKey, does it really matter what the argument value is?
Asking another way, are two instances of PageStorageKey with the same string argument unique or equivalent?
In other languages, things like this use their storage reference to disambiguate, so the actual text linked to the object doesn't matter.
I'm trying to determine if I need to ensure that all PageStorageKeys in my application have to have unique strings as a seed, or can I just boilerplate them all to the same value?
var psKey1 = PageStorageKey<String>('Am I the same or different than my sibling?');
var psKey2 = PageStorageKey<String>('Am I the same or different than my sibling?');
It appears two PageStorageKeys with the same String initializer are considered the same.
I wrote a short example and ran it under debugging
Test 1
var psKey1 = PageStorageKey('am I a clone');
var psKey2 = PageStorageKey('am I a clone');
var equivalent = psKey1 == psKey2;
equivalent = true;
Test 2
var psKey1 = PageStorageKey('am I a clone');
var psKey2 = PageStorageKey('am I not a clone');
var equivalent = psKey1 == psKey2;
equivalent = false;
I will be proceeeding under the presumption that all PageStorageKeys need to be unique within a given scope.

how to retain the value of the last iteration on a sequence in for-in

var index: Int=0
for index in 1...3{
print(index)
}
print(index)//prints 0
If I run this code, the last print gives 0, which means the index inside the for-in is not the same as outside. Seems like this force declares a new constant.
I am looking for similar way to retain the last value in the sequence
I know I can do
var index_out: Int=0
for index in 1...3{
print(index)
index_out = index
}
print(index_out)
If you're gonna loop through something and want to know the end index just use the amount of times you looped through it:
let n = 3
for index in 1...n{
print(index)
}
print(n)
Or with an array:
let array = [Int](count: 10, repeatedValue: 2)
for index in 0..<array.count {
print(index)
}
print(array.count)
The way you know you can do it is how to do it, for loops create their own scope. Anything declared inside of a set of { } means that it's for use within that scope only.
You can also use the way for in is implemented with an outer scope generator and while:
var generator = sequence.generate()
var element = generator.next()
while let x = generator.next() {
element = x
}
// element is nil if the sequence is empty
print(element)
this is only another way to do this but personally I think you should avoid that.
A much nicer solution would be with reduce (in Swift 1.x: global function, in Swift 2: as method)
// with default value
let lastElement = sequence.reduce(default) { $1 }
// if default should be nil you have to provide the explicit type because it cannot be inferred; probably use an extension:
// as extension
extension SequenceType {
var last: Self.Generator.Element? {
return self.reduce(nil) { $1 }
}
}
There is no way to do it, since it is in different scope than your method. But you also SHOULD NOT do what you do, to assign to your index on each iteration - that is wasteful. Instead, just increase index after you are done:
var data = []
var lastIndex = 0
for (index, object) in enumerate(data) {
...
}
lastIndex += data.count
Or, if you need to break for cycle for some reason, just assign it from inside of the cycle just before you break.

Swift: how to assign an optional by reference

Given the following code:
class Node {
var value: Int
var left: Node?
var right: Node?
init (value: Int) {
self.value = value
}
}
root = Node(value: 200)
Then the following code assigns a new node to root.left:
var temp1 = root
temp1!.left = Node(value: 400)
But the following does not assign a new node to root.right:
var temp2 = root!.right
temp2 = Node(value: 300)
Presumably in the last code snippet root!.right is assigned to temp2 by value, if so then is there a way of assigning it by reference?
This actually has nothing to do with optionals-- the same behavior would occur if the properties Node.left and Node.right were not optionals. Rather, this has to do with Swift class properties.
In your former example, you are pointing temp1 to the same class instance that root points to. Thus, root and temp1 are the same instance of Node, so when you set a property in one, it changes when you get it from the other.
In your latter example, you are getting the value of root!.right (which is currently nil) and setting it a new variable, temp2. You are creating a new class instance, so you end up with two separate class instances. When you assign to root.right, it will have no effect on temp2 (and vice versa).

write protection in for loop?

One strange behaviour: I have several objects and arrays:
for image in images {
for nextID in image.parts {
if nextID.number != 0 {
if let n = primaryLookUp[nextID.number] {
image.parts[0].newID = 0
nextID.newID = 0 // cannot assign!!!
}
}
}
nextID is simply going through the array of .parts. Does ist become a "let" assignment so I couldn't change anything later on? The
image.parts[0].newID = 0
is valid!
I believe this is the explanation for what you are seeing:
The value of a loop variable is immutable, just as if it had been assigned with let.
In your first loop, images is an array of objects (defined by a class). Since a class object is a reference type, you can alter the fields of the object. Only the loop variable image in that case cannot be assigned.
In your second loop, image.parts is an array of structs. Since a struct is a value type, the entire nextID and its fields will be immutable within the loop.
If you add var to the second loop, you will be able to assign to nextID.newID:
for image in images {
for var nextID in image.parts {
if nextID.number != 0 {
if let n = primaryLookUp[nextID.number] {
image.parts[0].newID = 0
nextID.newID = 0 // this now works!!!
}
}
}
}
but, you are changing a copy of the nextID (since structures copies are by value) and you are not changing the nextID contained in the original image object.

Append a class object to an array

I am having trouble with the syntax here. Basically I created a simple class and hoping to add the object of that class to an Array.
class simpleClass {
var aNum = Int()
var aWord = String()
init(thisNum:Int,thisString:String)
{
aNum = thisNum
aWord = thisString
}
}
var aObj:simpleClass
var aArray:Array<simpleClass>
aObj = simpleClass(thisNum:12,thisString:"Test")
aArray.append(aObj)
As you can see I have created an object of simpleClass and trying to append it to an array of type simpleClass. However, I receive an error saying
passed by reference before being initialized
I guess I must be missing something in the syntax. Hoping someone out there could point out my mistake.
thanks,
sweekim
You need to assign an array to the array variable.
var aArray:Array<simpleClass> = []
Or if you prefer,
var aArray = Array<simpleClass>()
Or even (my preference)
var aArray: [simpleClass] = []
Or
var aArray = [simpleClass]()
Better yet you could even reorder things and do this:
var aArray = [simpleClass(thisNum:12,thisString:"Test")]
instead of the whole 4 last lines.
Incidentally, you might find it better to declare your class like this:
class simpleClass {
var aNum: Int
var aWord: String
init(thisNum:Int,thisString:String) {
aNum = thisNum
aWord = thisString
}
}
This types aNum and aWord, but does not assign them values, since you then do that in the init method. The reason being, if you ever forgot to assign a value in init the compiler will warn you, whereas if you default them, it won’t. It’s fine to default them instead, but then don’t include them in an init method – one or the other is best, both is a bit redundant and can lead to mistakes.
Change this line:
var aArray:Array<simpleClass>
To this:
var aArray:Array<simpleClass> = []
You were declaring the array type but you forgot to make any array. If you actually look at the error message, it tells you exactly that - you didn't initialize the variable.
Also I think you didn't quite declare your instance of simpleClass correctly. I did this to silence the errors:
var aArray:Array<simpleClass> = []
let aObj:simpleClass = simpleClass(thisNum:12,thisString:"Test")
aArray.append(aObj)
Note the way an instance of simpleClass is created.