CSE116的学习笔记-Lec3-5:Immutability
Immutability
Immutable Objects
- Values stored in state variables cannot change
- Immutable objects are stored on the heap just like any other object
- But we don’t worry about the state changing when we pass the reference to a method / function
- What if an immutable object needs to change state?
- Create a copy of the object with the change applied
- This ImmutableCounter class takes an initial value in its constructor and has methods to increment and decrement this value
- The internal Int is a value and cannot change
- It also can’t be accessed (Artificial restriction to show more recursion)
1 | class ImmutableCounter(counter: Int) { |
1 | def updateCounter(n: Int, counter: ImmutableCounter): ImmutableCounter = { |
- Since the Int cannot change
- We simulate changes by creating a new object on the heap with the change applied
- Create and return a new ImmutableCounter whenever a “change” is made
- Since we return a new ImmutableCounter
- We must use this return value or we will not see the change
- What if we want to increment this object 10 times?
- Since we [artificially] restrict access to the Int we can only increment and decrement
- We could use a loop and reassign a variable at each iteration (requires var)
- What if we want to increment this object 10 times?
- Use a recursive approach
- Base case if n == 0
- Recursively increment / decrement and make a recursive call with n closer to 0
Strings are Immutable
1 | def nerf(input: String): Unit = { |
- The main method creates a new String on the stack and passes a reference to it to the nerf method
- We would usually expect to see changes made to this object by the method
- The method “replaces” all instance of the substring “6” with “5”
- The “change” is made by creating a new String
- Since this method has a return type of Unit, the reference is not returned
- The String is still on the heap
- After the call to nerf resolves
- The stack is in the same state as it wes before the method call
- There is an extra String on the Heap
- [It can be garbage collected]
- The next method call also creates a new String on the heap
- Replaces “116” with “250”
- Method returns a reference to the new String that was created
- The reference is stored in a variable in the main method
- We create another new String in main
- The reference is never stored in a variable
- Never see this String in our code
List are Immutable
1 | def firstNPrimes(n: Int): List[Int] = { |
- Recursive calls are added to the stack until we reach the base case of n == 1
- Create a new immutable List on the heap
- The base case returns a reference to the List it created
- This List is immutable so it will never change
- Even though its reference is passed around different frames
- The previous recursive call gets this returned reference
- Accesses that List on the heap
- The reference is passed to the next method call
- This is the reference behavior we expect
- Since 3 is not divisible by 2
- Return the base case of i
- Get return value of 3 and prepend it to the List of know primes
- But Lists are immutable!
- Create a new List with 3 prepended
- A reference to the new List is returned
- The original List remains on the heap an is unchanged
- Important:
- If another part of our program has the reference @1 stored in q variable
- Nothing we do can interfaere with its computation
- The first recursive call gets the reference @2
- Continues its computation with this reference
- Make a call to findPrime based on the List @2
- Base case is false since 4%2 == 0
- Recursive call is made to check if the next integer is prime
- Hit the base case since 5 is prime
- Return 5 up the recursion
- With the return value of 5
- firstNPrimes can finish its computation
- Create another new List on the heap
- Return the new lists containing all three primes
- Main gets the List at reference @3
- The other two Lists are sitll on the Heap and are unchanged
- [Not garbage collected. More details coming]
- The primes 5,3,2 are printed to the console
Lecture Question
Restriction:
No state is allowed in this question. Specifically, the keyword “var” is banned. (ie. You are expected to use a recursive solution)
Question:
In a package named “functions” write a class named Point with the following features:
- Has a constructor that takes 2 values (Use val) of type Double named “x” and “y”
- A method named “add” that takes a Point and returns a Point that is the component-wise addition of this Point and the input Point
- Ex. (1.0, 2.0) + (4.0, 1.0) = (5.0, 3.0)
- A method named “multiplyByScalar” that takes a Double and returns a new Point that is this Point multiplied by the input
- Ex. 5.0 * (1.0, 2.0) = (5.0, 10.0)
Testing:
In a package named “tests” create a class named “TestPoint” as a test suite that tests all the functionality listed above
All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Comment
TwikooValine