Arc Forumnew | comments | leaders | submitlogin
2 points by fallintothis 3930 days ago | link | parent

Disk serialization of variables & tables is already part of Arc 3.1's fromdisk, diskvar, disktable, and todisk:

  $ arc
  Use (quit) to quit, (tl) to return here after an interrupt.
  arc> (disktable h "/tmp/nested")
  #hash()
  arc> (= h (obj this "this" that 3 nested-hash-table (obj one "one" two "two" three 3) some-list (list 1 2 "three" 4)))
  #hash((that . 3) (some-list . (1 2 "three" 4 . nil)) (this . "this") (nested-hash-table . #hash((one . "one") (two . "two") (three . 3))))
  arc> (todisk h)
  ((nested-hash-table #hash((one . "one") (two . "two") (three . 3))) (this "this") (some-list (1 2 "three" 4)) (that 3))
  arc> (quit)
  $ cat /tmp/nested && echo
  ((nested-hash-table #hash((one . "one") (two . "two") (three . 3))) (this "this") (some-list (1 2 "three" 4)) (that 3))
  $ arc
  Use (quit) to quit, (tl) to return here after an interrupt.
  arc> (disktable nt "/tmp/nested")
  #hash((that . 3) (some-list . (1 2 "three" 4)) (this . "this") (nested-hash-table . #hash((one . "one") (two . "two") (three . 3))))
But, as I'm sure you're aware, the error with the above is that the serialized table (returned by todisk) has a literal Scheme #hash object nested inside, and when you read that back in, it's immutable:

  arc> (= (nt "this") "THIS")
  "THIS"
  arc> (nt "this")
  "THIS"
  arc> (= (nt 'some-list) (list 5 6 "seven"))
  (5 6 "seven")
  arc> (nt 'some-list)
  (5 6 "seven")
  arc> nt
  #hash((that . 3) (some-list . (5 6 "seven" . nil)) (this . "this") (nested-hash-table . #hash((one . "one") (two . "two") (three . 3))) ("this" . "THIS"))
  arc> (= ((nt 'nested-hash-table) 'one) "ONE")
  Error: "hash-set!: contract violation\n  expected: (and/c hash? (not/c immutable?))\n  given: #hash((one . \"one\") (two . \"two\") (three . 3))\n  argument position: 1st\n  other arguments...:\n   one\n   \"ONE\""
So, the actual salient operation here has little to do with immutable tables, but rather "deep copying" them, an operator that vanilla Arc lacks. It only has copy:

  (def copy (x . args)
    (let x2 (case (type x)
              sym    x
              cons   (copylist x) ; (apply (fn args args) x)
              string (let new (newstring (len x))
                       (forlen i x
                         (= (new i) (x i)))
                       new)
              table  (let new (table)
                       (each (k v) x 
                         (= (new k) v))
                       new)
                     (err "Can't copy " x))
      (map (fn ((k v)) (= (x2 k) v))
           (pair args))
      x2))
But we could model a deep-copy off of that:

  ; (map deep-copy xs) wouldn't work on dotted lists, hence this helper
  (def deep-copylist (xs)
    (if (no xs)
         nil
        (atom xs)
         (deep-copy xs)
         (cons (deep-copy (car xs))
               (deep-copylist (cdr xs)))))

  (def deep-copy (x . args)
    (let x2 (case (type x)
              sym    x
              char   x
              int    x
              num    x
              cons   (deep-copylist x)
              string (copy x)
              table  (let new (table)
                       (each (k v) x
                         (= (new (deep-copy k)) (deep-copy v)))
                       new)
                     (err "Can't deep copy " x))
      (map (fn ((k v)) (= (x2 (deep-copy k)) (deep-copy v)))
           (pair args))
      x2))
Then we have

  arc> (disktable nt "/tmp/nested")
  #hash((some-list . (1 2 "three" 4)) (this . "this") (nested-hash-table . #hash((one . "one") (two . "two") (three . 3))) (that . 3))
  arc> (= nt (deep-copy nt))
  #hash((nested-hash-table . #hash((three . 3) (one . "one") (two . "two"))) (this . "this") (that . 3) (some-list . (1 2 "three" 4 . nil)))
  arc> (= (nt "this") "THIS")
  "THIS"
  arc> (= ((nt 'nested-hash-table) 'one) "ONE")
  "ONE"
  arc> (= (nt 'some-list) (list 5 6 "seven"))
  (5 6 "seven")
  arc> nt
  #hash((nested-hash-table . #hash((three . 3) (one . "ONE") (two . "two"))) (this . "this") (that . 3) ("this" . "THIS") (some-list . (5 6 "seven" . nil)))
You could build a macro atop of fromdisk to handle deep copying automatically.

I seem to remember discussion about deep copying before, but all I could find was http://arclanguage.org/item?id=16979.