Arc Forumnew | comments | leaders | submitlogin
3 points by fallintothis 4213 days ago | link | parent

This is a tricky one! Turns out you're absolutely right, actually, this is sort of a bug (if you expect a different behavior of the function insert-sorted).

You're right in thinking that x and y share the same reference, like

  y -.
      \
  x ---+--> [ * | * ]
              |   |
              1   `--> [ * | * ]
                         |   |
                         3   `--> [ * | * ]
                                    |   |
                                    5   `--> nil
The thing is, the only real way to get at pointers in Arc is to use sref, scar and scdr. Those will actually mutate the cons cell sitting in memory. We can verify this, plus the fact that x and y share the same reference, by using (say) scar:

  arc> (= y (= x '(1 3 5)))
  (1 3 5)
  arc> x
  (1 3 5)
  arc> y
  (1 3 5)
  arc> (macex '(= (car x) 2)) ; '= expands into a form that uses 'scar
  ((fn () (atwith (gs1731 x gs1732 2) ((fn (val) (scar gs1731 val)) gs1732))))
  arc> (= (car x) 2)
  2
  arc> x
  (2 3 5)
  arc> y
  (2 3 5)
The problem is that insort doesn't truly mutate the cons cell of its argument. It's a lazy-man's "destructive", because it uses the zap macro to reassign x to a separate, insorted version of the list:

  arc> (= y (= x '(1 3 5)))
  (1 3 5)
  arc> (macex '(insort < 2 x))
  (atomic-invoke
    (fn ()
      (withs (gs1736 x
              gs1735 [insert-sorted < 2 _])
        ((fn (gs1737) (assign x gs1737))
         (gs1735 gs1736)))))
Notice how the expansion calls insert-sorted on x, then uses (assign x ...) to change where x points. insert-sorted is just a normal, FP-style function that doesn't mutate its arguments, instead consing together a new list in memory:

  (def insert-sorted (test elt seq)
    (if (no seq)
         (list elt) 
        (test elt (car seq)) 
         (cons elt seq)
        (cons (car seq) (insert-sorted test elt (cdr seq)))))
So, the pointer diagram will look like

  y -.
      \
  x    `--> [ * | * ]
  |           |   |
  |           1   `--> [ * | * ]
  |                      |   |
  |                      3   `--> [ * | * ]
  |                                 |   |
  |                                 5   `--> nil
  `-------> [ * | * ]
              |   |
              1   `--> [ * | * ]
                         |   |
                         2   `--> [ * | * ]
                                    |   |
                                    3   `--> [ * | * ]
                                               |   |
                                               5   `--> nil
If you want to mutate the cons cell that x points to, you'd instead have to do something like

  arc> (= y (= x '(1 3 5)))
  (1 3 5)
  arc> (let insorted (insert-sorted < 2 x)
         (scar x (car insorted))
         (scdr x (cdr insorted)))
  (2 3 5)
  arc> x
  (1 2 3 5)
  arc> y
  (1 2 3 5)
That way, your pointer diagram would look like

  y -.        1
      \        
  x ---+--> [ * | * ]
             /     \
            /       \        [ * | * ]
           /         \         |   |
          /           \        3   `--> [ * | * ]
         /             \                  |   |
        /               |                 5   `--> nil
        |   [ * | * ]   |
        |     |   |     |
        `---> 1   `-----+---> [ * | * ]
                                |   |
                                2   `--> [ * | * ]
                                           |   |
                                           3   `--> [ * | * ]
                                                      |   |
                                                      5   `--> nil
Then the free-floating cons-cell from the insert-sorted, the old car (the 1), and the old cdr (the (3 5)) would all be garbage-collected eventually. (Modulo implementation details, of course, like the numbers actually sharing the same spots in memory instead of being duplicated. But it makes the diagram cleaner.)


2 points by dram 4213 days ago | link

That's the point.

But your code only make first cell of x to be destructive.

  (let insorted (insert-sorted < 2 x)
         (scar x (car insorted))
         (scdr x (cdr insorted)))
I wrote some more destructive code, see: http://www.arclanguage.org/item?id=17838

-----

2 points by akkartik 4213 days ago | link

Ah, I see what you and dram mean. zck pointed this out as well last year: http://arclanguage.org/item?id=17074.

-----