The first example is correctly explained by newBert: When deleting a context, then all symbols in it get deleted, and the context symbol is demoted to a normal symbol.
Only this way it is possible to have variables holding contexts:
Code: Select all
(setq FISH:test 10) => 10
(setq FOO FISH) => FISH
FOO:test => 10
FOO is now a variable holding a context. FOO:test and FISH:test point to the same piece of memory. If I do:
Code: Select all
(set 'FOO:test 1234) => 1234
FISH:test => 1234
then FOO and FISH point to the same context. When the interpreter sees: CCC:xxx, it checks first if CCC exists as a context or a normal variable. If neither has been seen before, CCC will be created as a context. If CCC exists already as a normal variable, the interpreter expects CCC to hold a context else will throw an error.
The only way to to elevate a normal symbol back to a context symbol is using the 'context' primitive itself.
Demoting context symbols to normal symbols after deletion was introduced in version 9.1.6 to make it possible to create a context from a local variable in a function. Jeff requested this to be able to create transient contexts, which do only exist during the life of the function execution:
Code: Select all
(define (foo x)
(let (ctx 999)
(println "ctx:" ctx)
(context 'ctx) ; create a context from local variable
(set 'ctx:x 123)
(println "current context:" (context))
(println "symbols in ctx: " (symbols ctx))
(println "ctx:x: " ctx:x)
(println "x:" x)
(delete 'ctx)
))
> (foo 10)
ctx:999
current context:ctx
symbols in ctx: (x)
ctx:x: 123
x:10
true
>
This construct is only possible using that demotion feature, because we cannot delete the local 'ctx' , which is part of the function defined. I don't think that transient contexts are a necessary feature, but Jeff felt very strong about this and came up with some interesting examples.
It is this new 'demotion' feature introduced in 9.1.6 which causes the crash observed in the second self-referential m35 example, when doing (setq C:C C) (delete 'C:C), or also when doing (set 'C:test C) (delete 'C:test). The deletion of C:test deletes at first the contents of it which is C itself.
'delete' is a low level newLISP function which has no usage in normal newLISP programming, but I will see if this special case can be taken care of without impact on code size or performance.
ps: fixed in 9.9.95, will delete without crash.