copying objects reference copy copies reference vs
play

Copying Objects: Reference Copy Copies: Reference vs. Shallow vs. - PowerPoint PPT Presentation

Copying Objects: Reference Copy Copies: Reference vs. Shallow vs. Deep Reference Copy c1 := c2 Copy the address stored in variable c2 and store it in c1 . Writing Complete Postconditions Both c1 and c2 point to the same object.


  1. Copying Objects: Reference Copy Copies: Reference vs. Shallow vs. Deep Reference Copy c1 := c2 ○ Copy the address stored in variable c2 and store it in c1 . Writing Complete Postconditions ⇒ Both c1 and c2 point to the same object. ⇒ Updates performed via c1 also visible to c2 . [ aliasing ] C a c1.a EECS3311 A: Software Design c1 Winter 2020 C HEN -W EI W ANG C a c2.a c2 3 of 39 Copying Objects Copying Objects: Shallow Copy Say variables c1 and c2 are both declared of type C . [ c1 , c2 : C ] Shallow Copy c1 := c2 . twin ● There is only one attribute a declared in class C . ○ Create a temporary, behind-the-scene object c3 of type C . ○ Initialize each attribute a of c3 via reference copy : c3 . a := c2 . a ● c1.a and c2.a are references to objects. ○ Make a reference copy of c3 : c1 := c3 ⇒ c1 and c2 are not pointing to the same object. [ c1 /= c2 ] ⇒ c1.a and c2.a are pointing to the same object. C ⇒ Aliasing still occurs: at 1st level (i.e., attributes of c1 and c2 ) a c1.a C c1 a c1.a c1 C C a c3 a c2.a c2 C a c2.a c2 2 of 39 4 of 39

  2. Copying Objects: Deep Copy Example: Collection Objects (1) Deep Copy ○ In any OOPL, when a variable is declared of a type that c1 := c2 . deep_twin corresponds to a known class (e.g., STRING , ARRAY , ○ Create a temporary, behind-the-scene object c3 of type C . LINKED LIST , etc.): ○ Recursively initialize each attribute a of c3 as follows: At runtime , that variable stores the address of an object of that type Base Case : a is primitive (e.g., INTEGER ). ⇒ c3 . a := c2 . a . (as opposed to storing the object in its entirety). Recursive Case : a is referenced. ⇒ c3 . a := c2 . a . deep_twin ○ Assume the following variables of the same type: ○ Make a reference copy of c3 : c1 := c3 ⇒ c1 and c2 are not pointing to the same object. local ⇒ c1.a and c2.a are not pointing to the same object. imp : ARRAY [ STRING ] old_imp : ARRAY [ STRING ] ⇒ No aliasing occurs at any levels. do C create { ARRAY [ STRING ]} imp . make_empty a c1.a imp . force ("Alan", 1) c1 imp . force ("Mark", 2) imp . force ("Tom", 3) C a c2.a. deep_twin c3 ● Before we undergo a change on imp , we “ copy ” it to old imp . ● After the change is completed, we compare imp vs. old imp . C a c2.a ● Can a change always be visible between “ old ” and “ new ” imp ? c2 5 of 39 7 of 39 Copying Objects Example: Collection Objects (2) a ● Variables imp and old imp store address(es) of some array(s). O1 ! Initial situation: name “Almaviva” ● Each “slot” of these arrays stores a STRING object’s address. landlord loved_one O3 ARRAY[STRING] O2 “Figaro” “Susanna” ! Result of: imp b := a b imp[2] imp[3] imp[1] O4 “Almaviva” c := a.twin STRING STRING STRING c value “Alan” value “Mark” value “Tom” d := a.deep_twin d name “Almaviva” O5 ?? landlord loved_one O7 O6 “Figaro” “Susanna” old_imp 6 of 39 8 of 39

  3. Reference Copy of Collection Object Shallow Copy of Collection Object (2) 1 old imp := imp 1 old imp := imp. twin 2 Result := old_imp = imp -- Result = true 2 Result := old_imp = imp -- Result = false 3 imp [2] := "Jim" 3 imp [2]. append ("***") 4 Result := 4 Result := 5 across 1 |..| imp . count is j 5 across 1 |..| imp . count is j 6 all imp [ j ] ∼ old_imp [ j ] 6 all imp [ j ] ∼ old_imp [ j ] 7 end -- Result = true 7 end -- Result = true Before Executing L3 After Executing L3 Before Executing L3 After Executing L3 ARRAY[STRING] ARRAY[STRING] ARRAY[STRING] old_imp ARRAY[STRING] imp imp STRING STRING STRING STRING STRING STRING old_imp imp value “Alan” value “Mark” value “Tom” value “Alan” value “Mark” value “Tom” STRING STRING STRING “Mark***” value “Alan” value “Mark” value “Tom” imp old_imp old_imp STRING STRING STRING STRING ARRAY[STRING] ARRAY[STRING] value “Alan” value “Mark” value “Tom” value “Jim” 9 of 39 11 of 39 Shallow Copy of Collection Object (1) Deep Copy of Collection Object (1) 1 old imp := imp. deep twin 1 old imp := imp. twin 2 Result := old_imp = imp -- Result = false 2 Result := old_imp = imp -- Result = false 3 imp [2] := "Jim" 3 imp [2] := "Jim" 4 Result := 4 Result := 5 across 1 |..| imp . count is j 5 across 1 |..| imp . count is j 6 all imp [ j ] ∼ old_imp [ j ] end -- Result = false 6 all imp [ j ] ∼ old_imp [ j ] 7 end -- Result = false Before Executing L3 After Executing L3 Before Executing L3 After Executing L3 ARRAY[STRING] STRING ARRAY[STRING] value “Jim” ARRAY[STRING] STRING ARRAY[STRING] value “Jim” imp imp STRING STRING STRING STRING STRING STRING imp imp value “Alan” value “Mark” value “Tom” value value value “Alan” “Mark” “Tom” STRING STRING STRING STRING STRING STRING STRING STRING STRING STRING STRING STRING value value value value “Alan” value “Mark” value “Tom” “Alan” “Mark” “Tom” value “Alan” value “Mark” value “Tom” value “Alan” value “Mark” value “Tom” old_imp old_imp old_imp old_imp ARRAY[STRING] ARRAY[STRING] ARRAY[STRING] ARRAY[STRING] 10 of 39 12 of 39

  4. Deep Copy of Collection Object (2) When are contracts complete? 1 old imp := imp. deep twin ● In post-condition , for each attribute , specify the relationship 2 Result := old_imp = imp -- Result = false between its pre-state value and its post-state value. 3 imp [2]. append ("***") 4 Result := ○ Eiffel supports this purpose using the old keyword. 5 across 1 |..| imp . count is j ● This is tricky for attributes whose structures are composite 6 all imp [ j ] ∼ old_imp [ j ] end -- Result = false rather than simple : Before Executing L3 After Executing L3 e.g., ARRAY , LINKED LIST are composite-structured. ARRAY[STRING] e.g., INTEGER , BOOLEAN are simple-structured. ● Rule of thumb: For an attribute whose structure is composite, ARRAY[STRING] imp we should specify that after the update: STRING STRING STRING imp value “Alan” value “Mark” value “Tom” 1. The intended change is present; and STRING STRING STRING “Mark***” value value value “Alan” “Mark” “Tom” 2. The rest of the structure is unchanged . STRING STRING STRING STRING STRING STRING value value value “Alan” “Mark” “Tom” value “Alan” value “Mark” value “Tom” ● The second contract is much harder to specify: ○ Reference aliasing [ ref copy vs. shallow copy vs. deep copy ] old_imp old_imp ○ Iterable structure [ use across ] ARRAY[STRING] ARRAY[STRING] 13 of 39 15 of 39 How are contracts checked at runtime? Account ○ All contracts are specified as Boolean expressions. class ○ Right before a feature call (e.g., acc.withdraw(10) ): ACCOUNT ● The current state of acc is called its pre-state . ● Evaluate pre-condition using current values of attributes/queries. inherit deposit ( a : INTEGER ) ● Cache values, via := , of old expressions in the post-condition . ANY do redefine is_equal end balance := balance + a e.g., old accounts[i].id [ old accounts i id ∶ = accounts[i].id ] ensure e.g., ( old accounts[i] ) . id [ old accounts i ∶ = accounts[i] ] create balance = old balance + a make end e.g., ( old accounts[i]. twin ) . id [ old accounts i twin ∶ = accounts[i]. twin ] e.g., ( old accounts )[ i ] . id [ old accounts ∶ = accounts ] feature -- Attributes is_equal ( other : ACCOUNT ): BOOLEAN owner : STRING do e.g., ( old accounts. twin )[ i ] . id [ old accounts twin ∶ = accounts. twin ] balance : INTEGER Result := e.g., ( old Current ) . accounts [ i ] . id [ old current ∶ = Current ] owner ∼ other . owner feature -- Commands and balance = other . balance e.g., ( old Current . twin ) . accounts [ i ] . id [ old current twin ∶ = Current . twin ] make ( n : STRING ) end ○ Right after the feature call: do end ● The current state of acc is called its post-state . owner := n ● Evaluate invariant using current values of attributes and queries. balance := 0 ● Evaluate post-condition using both current values and “cached” end values of attributes and queries. 14 of 39 16 of 39

Recommend


More recommend