#+Title: Testing out the memory model of various languages #+Author: Mark Armstrong #+Description: … * Ruby :PROPERTIES: :CUSTOM_ID: Ruby :END: Unlike the C-like languages, in Ruby, assignment between variables never copies the value. Instead, an assignment ~y = x~ makes the variable ~y~ an /alias/ (an alternate name) for ~x~. ** Non-mutable values :PROPERTIES: :CUSTOM_ID: Non-mutable-values :END: In addition, for /non-mutable/ types such as integers, assignments of variables to values simply makes the variable an alias for the value. We can see this by examining the ~object_id~ (Ruby's reference type) of ~x~ and ~y~ below. They both refer to the same object, ~5~. /Any/ way we have to “store” ~5~ will have the same ~object_id~, because ~5~ is immutable; only one copy can exist. #+begin_src ruby :results output x = 5 y = x puts "5's object_id is #{5.object_id}" puts "x's object_id is #{x.object_id}" puts "y's object_id is #{y.object_id}" #+end_src #+RESULTS: : 5's object_id is 11 : x's object_id is 11 : y's object_id is 11 ** Mutable values :PROPERTIES: :CUSTOM_ID: Mutable-values :END: For mutable values, more than one copy of the value may exist. For instance, strings are mutable, so in the below ~x~ and ~y~ refer to different instances of the same string. #+begin_src ruby :results output x = "hello world" y = "hello world" puts "(A new) \"hello world\"'s object_id is #{"hello world".object_id}" puts " x's object_id is #{x.object_id}" puts " y's object_id is #{y.object_id}" #+end_src #+RESULTS: : (A new) "hello world"'s object_id is 50455855907340 : x's object_id is 50455855907380 : y's object_id is 50455855907360 However, assignment between variables (assignment of the form ~y = x~) still creates aliases. #+begin_src ruby x = "hello world" y = x puts "(A new) \"hello world\"'s object_id is #{"hello world".object_id}" puts " x's object_id is #{x.object_id}" puts " y's object_id is #{y.object_id}" #+end_src ** The problem with aliases :PROPERTIES: :CUSTOM_ID: The-problem-with-aliases :END: … * F# :PROPERTIES: :CUSTOM_ID: F# :END: ** Immutability is the default :PROPERTIES: :CUSTOM_ID: Immutability-is-the-default :END: As is often the case in functional languages, variables in F# are by default immutable. #+begin_src fsharp :results output let x = 10 printfn "x is immutable, so while in scope it will always be %d" x #+end_src #+RESULTS: : x is immutable, so while in scope it will always be 10 : val x : int = 10 Note that ~x~ might be shadowed by another declaration of ~x~ (though we can't redeclare it in the same scope). ** The ~mutable~ keyword :PROPERTIES: :CUSTOM_ID: The-~mutable~-keyword :END: F# provides some support for imperative programming by allowing a variable to be declared ~mutable~, so its value can be updated. This update (assignment) is written using the left-facing arrow ~<-~. #+begin_src fsharp :results output let mutable x = 10 printfn "x is mutable, so even though right now it's value is %d..." x x <- x + 1 printfn "it's value can change to %d!" x #+end_src #+RESULTS: : x is mutable, so even though right now it's value is 10... : it's value can change to 11! : val mutable x : int = 11 ** Mutability by references :PROPERTIES: :CUSTOM_ID: Mutability-by-references :END: F# also includes /reference/ types which allow mutability. #+begin_src fsharp :results output let mutable y = ref 2 printfn "The identifier y is bound to a reference to %d." !y printfn "y is actually a record %A" y y := 3 printfn "Now y's reference points to %d instead." !y printfn "What happened is that y is now the record %A" y #+end_src #+RESULTS: : The identifier y is bound to a reference to 2. : y is actually a record {contents = 2;} : Now y's reference points to 3 instead. : What happened is that y is now the record {contents = 3;} : val y : int ref = {contents = 3;} * Oz :PROPERTIES: :CUSTOM_ID: Oz :END: ** Single assignment :PROPERTIES: :CUSTOM_ID: Single-assignment :END: The result of this code is obvious; ~X~ becomes the sum of ~2~ and ~3~, so we get ~5~ in the browser. #+begin_src oz :results output :noweb yes declare X Y Z in Y = 2 Z = 3 X = Y + Z {Browse X} #+end_src #+RESULTS: If we try to run the following code, what should the result be? In the single-assignment store model, which is a kernel of Oz, the assignment ~X = Y + Z~ will block until we know what ~Y~ and ~Z~ are. So we never get output if we just feed this to the virtual machine, because it gets stuck. (We do get some type information; it knows that ~Y~ and ~Z~ are ~char~ type, since they are added, and we get a long list of potential types for ~X~). #+begin_src oz :results output :noweb yes declare X Y Z in X = Y + Z Y = 2 Z = 3 {Browse X} #+end_src #+RESULTS: We can feed the lines ~Y = 2~ and ~Z = 3~ (the command ~C-. C-l~ feeds one line), and if we do so, then we get the output. ** Incorporating the treading into the code :PROPERTIES: :CUSTOM_ID: Incorporating-the-treading-into-the-code :END: Manually feeding lines is a hassle. We can automate it away by explicitely threading our code. #+begin_src oz :results output :noweb yes declare X Y Z in thread X = Y + Z end thread Y = 2 end thread Z = 5 end {Browse X} #+end_src #+RESULTS: ** Order doesn't matter :PROPERTIES: :CUSTOM_ID: Order-doesn't-matter :END: #+begin_src oz :results output :noweb yes declare X Y Z in thread X = Y + Z end thread {Delay 5000} Y = 2 end thread {Delay 5000} Z = 5 end {Browse X} #+end_src #+RESULTS: ** Something neat – unification A variable binding may end up binding more than just the variable on the left, due to /unification/. During unification, the system makes whatever bindings are necessary to /unify/ the two sides of the ~=~. “Assignment” is a trivial normalisation; just make the (unbound) variable on the left the same as the value on the right. In the more general case, we can try to unify partial values, as in #+begin_src oz :results output :noweb yes declare X Y A B in thread X = [3 2] end thread Y = [1 B] end thread X = Y end {Browse X} #+end_src #+RESULTS: Note that the left hand side need not be just an identifier. #+begin_src oz :results output :noweb yes declare A B in % Unify these lists! [A 2] = [1 B] {Browse A} {Browse B} #+end_src #+RESULTS: