test: document Luerl reference semantics for ao.unset #869
test: document Luerl reference semantics for ao.unset #869Lucifer0x17 wants to merge 3 commits intoedgefrom
Conversation
egression test for the patch@1.0 sentinel pattern. Demonstrates that passing a full table into an outbox-like container and then setting a key to nil erases it from both sides. Hence, there is an erratic behaviour in the patched state.
egression test for the patch@1.0 sentinel pattern. Demonstrates that passing a full table into an outbox-like container and then setting a key to nil erases it from both sides. Hence, there is an erratic behaviour in the patched state. Co-authored-by: Jack Frain <jfrain99@gmail.com>
…tics' into test/luerl-table-reference-semantics
|
Interesting, but I am confused! I thought the idea here was that the sending mechanics from If it is |
No, we are not. The test just isolates the behaviour. It imitates the same values that |
#829 introduced the
ao.unsetsentinel for removing fields frompatch@1.0cached state. It addedconvert_unset_values/1at the HB boundary so"__ao-unset__"strings get converted to theunsetatom thatdev_message:set/3treats as a key removal (which in itself was a bug). But the fix only works, till the"__ao-unset__"reaches to HB. Found out, it doesn't always.The remaining foot-gun
ao.send or Send()shallow-clones top-level keys of the message. When a handler does:...the outbox entry's routes field is a
#trefpointing to the same Luerl heap table as the global Routes. The post-Send, Routes[owner] = nil callsttdict:eraseon the shared table. By the time the Lua func returns andluerl:call_function_decwalks the heap to decode the outbox, the sentinel key is gone.convert_unset_valuesnever sees it. patch@1.0 device never learns the key should be removed.The pattern that works
Use a fresh small table and do not mutate the source between Send & the decode boundary.
-- Bad: reference leak, nil erases sentinel before patch@1.0 sees it
-- Good: targeted small table, no shared ref to mutate
The good pattern is O(1), explicit about intent, and cheaper computation than shallow-cloning the full table inside ao.send (which can be used when there is a multiple update in a single call).
This PR
Adds
ao_unset_reference_bug_testindev_lua.erlwith a companion Lua func intest/test.lua. Two assertions document both semantics:Locks in the Luerl reference behavior as a contract and gives future lua process authors an executable reference for the right pattern.