Last active
December 24, 2015 18:59
-
-
Save taoeffect/6847427 to your computer and use it in GitHub Desktop.
Failed attempt to create a "Perfect Automatic Reference Counting" scheme. This file has been edited. The original attempt can be found here: http://www.newlispfanclub.alh.net/forum/viewtopic.php?f=15&t=3151
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(define (Node.) | |
; for the sake of this example, let's say that this function | |
; is a "constructor" that returns a symbol pointing to a map. | |
) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; DECLARE "METHODS" FOR NODE ;; | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
(define (Node.set-paret this parent) | |
(setf (:parent this) parent)) | |
(define (Node.set-child this child) | |
(setf (:child this) child) ; Whatever value used to be in (:child this) | |
; has its RC decremented, and the new value | |
; (child) has its RC incremented. | |
(.set-parent child this)) | |
; like `set-child`, but assumes that we're acting on the "base node" | |
; and therefore adds the child to the end of the list | |
(define (Node.add-child this child) | |
(if-let (last (:last this)) | |
(.set-child last child) | |
(.set-child this child)) | |
(setf (:last this) child)) | |
;;;;;;;;;;;;;;;;;;;; | |
;; BEGIN EXAMPLE! ;; | |
;;;;;;;;;;;;;;;;;;;; | |
; At this point firstNode doesn't exist, so it doesn't have a RC. | |
; setup our 5-node circle | |
(set 'firstNode (Node.)) ; parent is nil | |
(dotimes (_ 4) ; add 4 children to it | |
(.add-child firstNode (Node.))) ; (Node.) returns a SYMBOL! | |
; Let's have a look at the RCs of the objects involved after one | |
; iteration of the loop above: | |
; | |
; (.add-child firstNode (Node.)): | |
; (.add-child <anon2>:this <anon2>:child | |
; BEFORE FUNCTION RUNS: | |
; | Object (type) | RC | Evaluates to | Has effect | | |
; +-----------------------+----+-----------------+-----------------------+ | |
; | 'MAIN:firstNode | 1 | 'Node.1 | 'Node.1 : 0->1 | | |
; | 'anon2:this (Symbol) | 1 | 'MAIN:firstNode | 'MAIN:firstNode: 1->2 | | |
; | 'anon2:child (Symbol) | 1 | 'Node.2 | 'Node.2 : 0->1 | | |
; | |
; WHILE FUNCTION RUNS: | |
; (.set-child this child): | |
; (.set-child <anon3>:this <anon3>:child | |
; BEFORE FUNCTION RUNS: | |
; | Object (type) | RC | Evaluates to | Has effect | | |
; +-----------------------+----+--------------+--------------------+ | |
; | 'anon3:this (Symbol) | 1 | 'anon2:this | 'anon2:this : 1->2 | | |
; | 'anon3:child (Symbol) | 1 | 'anon2:child | 'anon2:child: 1->2 | | |
; | |
; WHILE FUNCTION RUNS: | |
; (setf (:child this) child) ; Setting child of Node.1 | |
; -> ['anon3:child: 1->2] | |
; | |
; (.set-parent child this) | |
; (.set-parent <anon4>:this <anon4>:parent | |
; BEFORE FUNCTION RUNS: | |
; | Object (type) | RC | Evaluates to | Has effect | | |
; +------------------------+----+--------------+--------------------+ | |
; | 'anon4:this (Symbol) | 1 | 'anon3:child | 'anon3:child: 2->3 | | |
; | 'anon4:parent (Symbol) | 1 | 'anon3:this | 'anon3:this : 1->2 | | |
; | |
; WHILE FUNCTION RUNS: | |
; ; note that: (:parent this) => (:parent this) -> (:parent Node.2) | |
; (setf (:parent this) parent) | |
; -> ['anon4:parent: 1->2] | |
; ) | |
; AFTER FUNCTION RUNS: | |
; -> ['anon4:this: 1->0] | |
; -> ['anon3:child: 3->2] | |
; -> ['anon4:parent RC: 2->1] | |
; ) | |
; AFTER FUNCTION RUNS: | |
; -> ['anon3:this : 2->1] | |
; -> ['anon3:child: 2->1] | |
; | |
; (setf (:last this) child) ; (:last 'anon2:this) => (:last 'MAIN:firstNode) | |
; -> ['anon2:child: 2->3] | |
; ) | |
; AFTER FUNCTION RUNS: | |
; -> ['anon2:this : 2->1] | |
; -> ['anon2:child: 3->2] | |
| Object (type) | RC | Evaluates to | | |
+--------------------------+----+-----------------+ | |
| 'MAIN:firstNode (Symbol) | 2 | 'Node.1 | | |
| 'Node.1 (Symbol) | 1 | Node.1 | | |
| Node.1 (Map) | 1 | <self> | | |
| 'Node.2 (Symbol) | 1 | Node.2 | | |
| Node.2 (Map) | 1 | <self> | | |
| 'anon2:this (Symbol) | 1 | 'MAIN:firstNode | | |
| 'anon2:child (Symbol) | 2 | 'Node.2 | | |
| 'anon3:this (Symbol) | 1 | 'anon2:this | | |
| 'anon3:child (Symbol) | 1 | 'anon2:child | | |
| 'anon4:parent (Symbol) | 1 | 'anon3:this | | |
Node.1 = {:child 'anon3:child, :last 'anon2:child} | |
Node.2 = {:parent 'anon4:parent} | |
; Before we go overboard and evaluate the entire loop, let's just | |
; make sure that PARC works in this "easy case". What if we were | |
; to stop the loop right now and do this: | |
(setf firstNode nil) ; firstnode, the symbol, now points to nil | |
; Does PARC work in this "easy case"? | |
'Node.1 [1->0] | |
| | |
+--> Node.1 [1->0] | |
| | |
+--> 'anon3:child [1->0] | |
| | | |
| +--> 'anon2:child [2->1] | |
| | |
+--> 'anon2:child [1->0] | |
| | |
+--> 'Node.2 [1->0] | |
| | |
+--> Node.2 [1->0] | |
| | |
+--> 'anon4:parent [1->0] | |
| | |
+--> 'anon3:this [1->0] | |
| | |
+--> 'anon2:this [1->0] | |
| | |
+--> firstNode [2->1] | |
; Yup! ^_^ | |
; PARC works just fine so far. | |
; | |
; However, we want a more complicated situation with 5 nodes all | |
; linking to one another in a circle. So let's proceed. | |
; Let's do another iteration of the loop to find out what the pattern is. | |
; We should also do it because the logic changes a little bit since after | |
; the first iteration firstNode will have a :last keyword set. | |
; | |
; Remember, it was: | |
; | |
; (dotimes (_ 4) ; add 4 children to it | |
; (.add-child firstNode (Node.))) ; (Node.) returns a SYMBOL! | |
; | |
; (.add-child firstNode (Node.)): | |
; .add-child <anon5>:this <anon5>:child | |
; BEFORE FUNCTION RUNS: | |
; | Object (type) | RC | Evaluates to | Has effect | | |
; +-----------------------+----+-----------------+------------------------+ | |
; | 'anon5:this (Symbol) | 1 | 'MAIN:firstNode | 'MAIN:firstNode: 2->3 | | |
; | 'anon5:child (Symbol) | 1 | 'Node.3 | 'Node.3 : 0->1 | | |
; | |
; WHILE FUNCTION RUNS: | |
; (if-let (last (:last this)) ; 'let1:last = (:last firstNode) = 'anon2:child | |
; (.set-child last child) ; this gets run! | |
; (.set-child this child)) | |
; | |
; ; 'let1:last is another anonymous symbol created by the if-let expression: | |
; | |
; | Object (type) | RC | Evaluates to | Has effect | | |
; +---------------+----+--------------+---------------------+ | |
; | 'let1:last | 1 | 'anon2:child | 'anon2:child [2->3] | | |
; | |
; (.set-child <anon6>:this <anon6>:child | |
; BEFORE FUNCTION RUNS: | |
; | Object (type) | RC | Evaluates to | Has effect | | |
; +-----------------------+----+--------------+--------------------+ | |
; | 'anon6:this (Symbol) | 1 | 'let1:last | 'let1:last : 1->2 | | |
; | 'anon6:child (Symbol) | 1 | 'anon5:child | 'anon5:child: 1->2 | | |
; | |
; WHILE FUNCTION RUNS: | |
; (setf (:child this) child) ; Setting child of Node.2 | |
; -> ['anon6:child: 1->2] | |
; | |
; (.set-parent child this) | |
; (.set-parent <anon7>:this <anon7>:parent | |
; BEFORE FUNCTION RUNS: | |
; | Object (type) | RC | Evaluates to | Has effect | | |
; +------------------------+----+--------------+--------------------+ | |
; | 'anon7:this (Symbol) | 1 | 'anon6:child | 'anon6:child: 2->3 | | |
; | 'anon7:parent (Symbol) | 1 | 'anon6:this | 'anon6:this : 1->2 | | |
; | |
; WHILE FUNCTION RUNS: | |
; (setf (:parent this) parent) ; (:parent this) -> (:parent Node.3) | |
; -> ['anon7:parent: 1->2] | |
; ) | |
; AFTER FUNCTION RUNS: | |
; -> ['anon7:this: 1->0] | |
; -> ['anon6:child: 3->2] | |
; -> ['anon7:parent: 2->1] | |
; ) | |
; AFTER FUNCTION RUNS: | |
; -> ['anon6:this : 2->1] | |
; -> ['anon6:child: 2->1] | |
; | |
; DON'T FORGET THE SCOPE CREATED BY `if-let'! | |
; -> ['let1:last: 2->1] | |
; | |
; (setf (:last this) child) ; (:last 'anon5:this) => (:last 'MAIN:firstNode) | |
; -> ['anon5:child: 2->3] | |
; -> ['anon2:child: 3->2] | |
; | |
; AFTER FUNCTION RUNS: | |
; -> ['anon5:this : 1->0] | |
; -> ['MAIN:firstNode: 3->2] | |
; -> ['anon5:child: 3->2] | |
; | |
; Thus, after the 2nd iteration, we have the following objects in memory: | |
| Object (type) | RC | Evaluates to | | |
+--------------------------+----+-----------------+ | |
| 'MAIN:firstNode (Symbol) | 2 | 'Node.1 | | |
| 'Node.1 (Symbol) | 1 | Node.1 | | |
| Node.1 (Map) | 1 | <self> | | |
| 'Node.2 (Symbol) | 1 | Node.2 | | |
| Node.2 (Map) | 1 | <self> | | |
| 'Node.3 (Symbol) | 1 | Node.3 | | |
| Node.3 (Map) | 1 | <self> | | |
| 'let1:last (Symbol) | 1 | 'anon2:child | | |
| 'anon2:this (Symbol) | 1 | 'MAIN:firstNode | | |
| 'anon2:child (Symbol) | 2 | 'Node.2 | | |
| 'anon3:this (Symbol) | 1 | 'anon2:this | | |
| 'anon3:child (Symbol) | 1 | 'anon2:child | | |
| 'anon4:parent (Symbol) | 1 | 'anon3:this | | |
| 'anon5:child (Symbol) | 2 | 'Node.3 | | |
| 'anon6:this (Symbol) | 1 | 'let1:last | | |
| 'anon6:child (Symbol) | 1 | 'anon5:child | | |
| 'anon7:parent (Symbol) | 1 | 'anon6:this | | |
; Notice that 'let1:last was introduced into the table, | |
; and 'anon5:this disappeared. | |
; | |
; Also note that the table above does not contain any keywords | |
; from the Node maps, and therefore it's not clear why some symbols | |
; are still around (like 'anon6:child) because it appears nothing is | |
; referencing them. They are being referenced by the keys in the map. | |
; In the case of 'anon6:child, it's being referenced by the :child | |
; key of Node.2. 'anon5:child is being referenced by 'anon6:child | |
; and the :last keyword of firstNode. | |
; | |
; Unfortunately, a clear pattern hasn't established itself yet. There | |
; has yet to be an obvious repetititive modification of the object table, | |
; so for proof's sake (so that you're not simply taking my word for it), | |
; let's go through one more iteration. The last iteration should be | |
; discernable from the third, because the branching logic is the same | |
; between the third and the fourth iteration. | |
; | |
; Once again, the loop we're iterating is: | |
; | |
; (dotimes (_ 4) | |
; (.add-child firstNode (Node.))) | |
; | |
; (.add-child firstNode (Node.)): | |
; .add-child <anon8>:this <anon8>:child | |
; BEFORE FUNCTION RUNS: | |
; | Object (type) | RC | Evaluates to | Has effect | | |
; +-----------------------+----+-----------------+------------------------+ | |
; | 'anon8:this (Symbol) | 1 | 'MAIN:firstNode | 'MAIN:firstNode: 2->3 | | |
; | 'anon8:child (Symbol) | 1 | 'Node.4 | 'Node.4 : 0->1 | | |
; | |
; WHILE FUNCTION RUNS: | |
; (if-let (last (:last this)) ; 'let2:last = (:last firstNode) = 'anon5:child | |
; (.set-child last child) ; this gets run! | |
; (.set-child this child)) | |
; | |
; ; 'let2:last is another anonymous symbol created by the if-let expression: | |
; | |
; | Object (type) | RC | Evaluates to | Has effect | | |
; +---------------+----+--------------+---------------------+ | |
; | 'let2:last | 1 | 'anon5:child | 'anon5:child [2->3] | | |
; | |
; (.set-child <anon9>:this <anon9>:child | |
; BEFORE FUNCTION RUNS: | |
; | Object (type) | RC | Evaluates to | Has effect | | |
; +-----------------------+----+--------------+--------------------+ | |
; | 'anon9:this (Symbol) | 1 | 'let2:last | 'let2:last : 1->2 | | |
; | 'anon9:child (Symbol) | 1 | 'anon8:child | 'anon8:child: 1->2 | | |
; | |
; WHILE FUNCTION RUNS: | |
; (setf (:child this) child) ; Setting child of Node.3 | |
; -> ['anon9:child: 1->2] | |
; | |
; (.set-parent child this) | |
; (.set-parent <anon10>:this <anon10>:parent | |
; BEFORE FUNCTION RUNS: | |
; | Object (type) | RC | Evaluates to | Has effect | | |
; +-------------------------+----+--------------+--------------------+ | |
; | 'anon10:this (Symbol) | 1 | 'anon9:child | 'anon9:child: 2->3 | | |
; | 'anon10:parent (Symbol) | 1 | 'anon9:this | 'anon9:this : 1->2 | | |
; | |
; WHILE FUNCTION RUNS: | |
; (setf (:parent this) parent) ; (:parent this) -> (:parent Node.4) | |
; -> ['anon10:parent: 1->2] | |
; ) | |
; AFTER FUNCTION RUNS: | |
; -> ['anon10:this: 1->0] | |
; -> ['anon9:child: 3->2] | |
; -> ['anon10:parent RC: 2->1] | |
; ) | |
; AFTER FUNCTION RUNS: | |
; -> ['anon9:this : 2->1] | |
; -> ['anon9:child: 2->1] | |
; | |
; DON'T FORGET THE SCOPE CREATED BY `if-let'! | |
; -> ['let2:last: 2->1] | |
; | |
; (setf (:last this) child) ; (:last 'anon8:this) => (:last 'MAIN:firstNode) | |
; -> ['anon8:child: 2->3] | |
; -> ['anon5:child: 3->2] | |
; | |
; AFTER FUNCTION RUNS: | |
; -> ['anon8:this : 1->0] | |
; -> ['MAIN:firstNode: 3->2] | |
; -> ['anon8:child: 3->2] | |
; | |
; Thus, after the 3rd iteration, we have the following objects in memory: | |
| Object (type) | RC | Evaluates to | | |
+--------------------------+----+-----------------+ | |
| 'MAIN:firstNode (Symbol) | 2 | 'Node.1 | | |
| 'Node.1 (Symbol) | 1 | Node.1 | | |
| Node.1 (Map) | 1 | <self> | | |
| 'Node.2 (Symbol) | 1 | Node.2 | | |
| Node.2 (Map) | 1 | <self> | | |
| 'Node.3 (Symbol) | 1 | Node.3 | | |
| Node.3 (Map) | 1 | <self> | | |
| 'Node.4 (Symbol) | 1 | Node.4 | | |
| Node.4 (Map) | 1 | <self> | | |
| 'let1:last (Symbol) | 1 | 'anon2:child | | |
| 'let2:last (Symbol) | 1 | 'anon5:child | | |
| 'anon2:this (Symbol) | 1 | 'MAIN:firstNode | | |
| 'anon2:child (Symbol) | 2 | 'Node.2 | | |
| 'anon3:this (Symbol) | 1 | 'anon2:this | | |
| 'anon3:child (Symbol) | 1 | 'anon2:child | | |
| 'anon4:parent (Symbol) | 1 | 'anon3:this | | |
| 'anon5:child (Symbol) | 2 | 'Node.3 | | |
| 'anon6:this (Symbol) | 1 | 'let1:last | | |
| 'anon6:child (Symbol) | 1 | 'anon5:child | | |
| 'anon7:parent (Symbol) | 1 | 'anon6:this | | |
| 'anon8:child (Symbol) | 2 | 'Node.4 | | |
| 'anon9:this (Symbol) | 1 | 'let2:last | | |
| 'anon9:child (Symbol) | 1 | 'anon8:child | | |
| 'anon10:parent (Symbol) | 1 | 'anon9:this | | |
; Now a clear pattern has emerged. For any subsequent iterations | |
; we simply: | |
; | |
; 1. Add 'Node.X and Node.X (where X is the iteration after 4) | |
; 2. Add 'letY:last (where Y is the iteration after 2) and point it | |
; at anon[Z+3]:child, where Z was the context number of the previous symbol | |
; (which was the most recent value of (:last firstNode) before we ran | |
; the iteration. | |
; 3. Add four extra symbols to the end of the table (following | |
; the self-evident pattern). | |
; | |
; Thus, after the fourth iteration of the loop we get the following Object+RC table: | |
| Object (type) | RC | Evaluates to | | |
+--------------------------+----+-----------------+ | |
| 'MAIN:firstNode (Symbol) | 2 | 'Node.1 | | |
| 'Node.1 (Symbol) | 1 | Node.1 | | |
| Node.1 (Map) | 1 | <self> | | |
| 'Node.2 (Symbol) | 1 | Node.2 | | |
| Node.2 (Map) | 1 | <self> | | |
| 'Node.3 (Symbol) | 1 | Node.3 | | |
| Node.3 (Map) | 1 | <self> | | |
| 'Node.4 (Symbol) | 1 | Node.4 | | |
| Node.4 (Map) | 1 | <self> | | |
| 'Node.5 (Symbol) | 1 | Node.5 | | |
| Node.5 (Map) | 1 | <self> | | |
| 'let1:last (Symbol) | 1 | 'anon2:child | | |
| 'let2:last (Symbol) | 1 | 'anon5:child | | |
| 'let3:last (Symbol) | 1 | 'anon8:child | | |
| 'anon2:this (Symbol) | 1 | 'MAIN:firstNode | | |
| 'anon2:child (Symbol) | 2 | 'Node.2 | | |
| 'anon3:this (Symbol) | 1 | 'anon2:this | | |
| 'anon3:child (Symbol) | 1 | 'anon2:child | | |
| 'anon4:parent (Symbol) | 1 | 'anon3:this | | |
| 'anon5:child (Symbol) | 2 | 'Node.3 | | |
| 'anon6:this (Symbol) | 1 | 'let1:last | | |
| 'anon6:child (Symbol) | 1 | 'anon5:child | | |
| 'anon7:parent (Symbol) | 1 | 'anon6:this | | |
| 'anon8:child (Symbol) | 2 | 'Node.4 | | |
| 'anon9:this (Symbol) | 1 | 'let2:last | | |
| 'anon9:child (Symbol) | 1 | 'anon8:child | | |
| 'anon10:parent (Symbol) | 1 | 'anon9:this | | |
| 'anon11:child (Symbol) | 2 | 'Node.5 | | |
| 'anon12:this (Symbol) | 1 | 'let3:last | | |
| 'anon12:child (Symbol) | 1 | 'anon11:child | | |
| 'anon13:parent (Symbol) | 1 | 'anon12:this | | |
; create a loop by having the child of the last node be the first node itself | |
(.set-child (:last firstNode) firstNode) | |
; To evaluate this we must know the value of firstNode before we call | |
; .set-child above. What is the value of firstNode then? | |
; | |
; Node.1 = {:child 'anon3:child :last 'anon11:child} | |
; | |
; Now, let's break it down: | |
; | |
; (.set-child <anon14>:this <anon14>:child | |
; BEFORE FUNCTION RUNS: | |
; | Object (type) | RC | Evaluates to | Has effect | | |
; +------------------------+----+-----------------+-----------------------+ | |
; | 'anon14:this (Symbol) | 1 | 'anon11:child | 'anon11:child : 2->3 | | |
; | 'anon14:child (Symbol) | 1 | 'MAIN:firstNode | 'MAIN:firstNode: 2->3 | | |
; | |
; WHILE FUNCTION RUNS: | |
; (setf (:child this) child) ; (:child this) => (:child Node.5) | |
; -> ['anon14:child: 1->2] | |
; | |
; (.set-parent child this) | |
; (.set-parent <anon15>:this <anon15>:parent | |
; BEFORE FUNCTION RUNS: | |
; | Object (type) | RC | Evaluates to | Has effect | | |
; +-------------------------+----+---------------+---------------------+ | |
; | 'anon15:this (Symbol) | 1 | 'anon14:child | 'anon14:child: 2->3 | | |
; | 'anon15:parent (Symbol) | 1 | 'anon14:this | 'anon14:this : 1->2 | | |
; | |
; WHILE FUNCTION RUNS: | |
; (setf (:parent this) parent) ; (:parent firstNode) = 'anon15:parent | |
; -> ['anon15:parent: 1->2] | |
; ) | |
; AFTER FUNCTION RUNS: | |
; -> ['anon15:this: 1->0] | |
; -> ['anon14:child: 3->2] | |
; -> ['anon15:parent: 2->1] | |
; ) | |
; AFTER FUNCTION RUNS: | |
; -> ['anon14:this : 2->1] | |
; -> ['anon14:child: 2->1] | |
; | |
; Here's the final table we're left with: | |
| Object (type) | RC | Evaluates to | | |
+--------------------------+----+-----------------+ | |
| 'MAIN:firstNode (Symbol) | 3 | 'Node.1 | | |
| 'Node.1 (Symbol) | 1 | Node.1 | | |
| Node.1 (Map) | 1 | <self> | | |
| 'Node.2 (Symbol) | 1 | Node.2 | | |
| Node.2 (Map) | 1 | <self> | | |
| 'Node.3 (Symbol) | 1 | Node.3 | | |
| Node.3 (Map) | 1 | <self> | | |
| 'Node.4 (Symbol) | 1 | Node.4 | | |
| Node.4 (Map) | 1 | <self> | | |
| 'Node.5 (Symbol) | 1 | Node.5 | | |
| Node.5 (Map) | 1 | <self> | | |
| 'let1:last (Symbol) | 1 | 'anon2:child | | |
| 'let2:last (Symbol) | 1 | 'anon5:child | | |
| 'let3:last (Symbol) | 1 | 'anon8:child | | |
| 'anon2:this (Symbol) | 1 | 'MAIN:firstNode | | |
| 'anon2:child (Symbol) | 2 | 'Node.2 | | |
| 'anon3:this (Symbol) | 1 | 'anon2:this | | |
| 'anon3:child (Symbol) | 1 | 'anon2:child | | |
| 'anon4:parent (Symbol) | 1 | 'anon3:this | | |
| 'anon5:child (Symbol) | 2 | 'Node.3 | | |
| 'anon6:this (Symbol) | 1 | 'let1:last | | |
| 'anon6:child (Symbol) | 1 | 'anon5:child | | |
| 'anon7:parent (Symbol) | 1 | 'anon6:this | | |
| 'anon8:child (Symbol) | 2 | 'Node.4 | | |
| 'anon9:this (Symbol) | 1 | 'let2:last | | |
| 'anon9:child (Symbol) | 1 | 'anon8:child | | |
| 'anon10:parent (Symbol) | 1 | 'anon9:this | | |
| 'anon11:child (Symbol) | 3 | 'Node.5 | | |
| 'anon12:this (Symbol) | 1 | 'let3:last | | |
| 'anon12:child (Symbol) | 1 | 'anon11:child | | |
| 'anon13:parent (Symbol) | 1 | 'anon12:this | | |
| 'anon14:this (Symbol) | 1 | 'anon11:child | | |
| 'anon14:child (Symbol) | 1 | 'MAIN:firstNode | | |
| 'anon15:parent (Symbol) | 1 | 'anon14:this | | |
Node.1 = {:child 'anon3:child, :last 'anon11:child, :parent 'anon15:parent} | |
Node.2 = {:parent 'anon4:parent :child 'anon6:child} | |
Node.3 = {:parent 'anon7:parent :child 'anon9:child} | |
Node.4 = {:parent 'anon10:parent :child 'anon12:child} | |
Node.5 = {:parent 'anon13:parent :child 'anon14:child} | |
; Drum roll!! Now is the moment of truth. If, after the next line completes, | |
; all we're left with is just the symbol 'MAIN:firstNode, | |
; then Perfect Automatic Reference Counting works perfectly! | |
(setf firstNode nil) ; firstnode, the symbol, now points to nil | |
'Node.1 [1->0] | |
| | |
+--> Node.1 [1->0] | |
| | |
+--> 'anon3:child [1->0] | |
| | | |
| +--> 'anon2:child [2->1] ; referenced by (:parent Node.3) | |
| | |
+--> 'anon11:child [3->2] | |
| | |
+--> 'anon15:parent [1->0] | |
| | |
+--> 'anon14:this [1->0] | |
| | |
+--> 'anon11:child [2->1] ; referenced by Node.4, etc. | |
; FAIL! anon11:child , 'anon2:child, 'let1:last | |
; | |
; Two cycles observed: | |
; | |
; 1. anon11:child is referenced by itself through Node.4 | |
; 2. anon2:child is referenced by itself through Node.2 via anon6:child | |
; anon2:child | |
; | | |
; let1:last | |
; ^ | |
; | | |
; 'anon5:child | |
; | | |
; 'anon6:child | |
; | | |
; 'Node.2 | |
; | | |
; 'anon2:child | |
; | |
; anon2:child is also referenced by anon11:child... | |
; | |
; | |
; 'anon11:child has the following 3 references: | |
; 1. anon12:child | |
; 1. (:child Node.4) | |
; 1. 'Node.4 | |
; 1. 'anon8:child | |
; 1. 'let3:last | |
; 1. 'anon12:this | |
; 1. 'anon13:parent | |
; 1. (:parent Node.5) <- 'Node.5 | |
; 1. 'anon11:child !!!! CYCLE !!! | |
; | |
; 2. (:last Node.1) -> ['anon11:child 3->2] GOT RID OF THIS | |
; 3. anon14:this [1->0]: ['anon11:child 2->1] GOT RID OF THIS | |
; 1. anon15:parent [1->0] | |
; | |
; 'anon2:child has: | |
; 1. anon3:child: GOT RID OF THIS via '[anon2:child 2->1] | |
; 2. let1:last | |
; 1. anon6:this | |
; 1. anon7:parent | |
; 1. (:parent Node.3) <- 'Node.3 | |
; 1. 'Node.3 | |
; 1. 'anon5:child | |
; 1. 'let2:last | |
; 1. 'anon9:this | |
; 1. 'anon10:parent | |
; 1. (:parent Node.4) <- 'Node.4 | |
; 1. 'anon8:child | |
; 1. 'let3:last | |
; 1. 'anon12:this | |
; 1. 'anon13:parent | |
; 1. (:parent Node.5) <- 'Node.5 | |
; 1. 'anon11:child !!!! CYCLE !!! | |
; 2. 'anon9:child | |
; 2. 'anon6:child | |
; 1. (:child Node.2) | |
; 1. 'Node.2 | |
; 1. anon2:child !!! CYCLE !!! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is an updated version of an original attempt at PARC posted online in 2009: http://www.newlispfanclub.alh.net/forum/viewtopic.php?f=15&t=3151