Should SET-WORD!s Propagate Undecayed Packs?

Packs are antiform blocks, which decay if not specifically handled.

>> pack [1 2]
== ~['1 '2]~  ; anti

>> a: pack [1 2]
== 1

>> a
== 1

From time to time, I've wondered if there's a good reason why the plain SET-WORD! shouldn't propagate the pack:

>> a: pack [1 2]
== ~['1 '2]~  ; anti  (hypothetical)

>> a
== 1

One rationale is that intuitively, a: should be a synonym for [a]:, e.g. "unpack one item" is implicit.

But that just bumps the question to the next one we might ask: why doesn't a multi-return without a "circled" result just evaluate to the whole pack?

It looks to make some sense at first, it allows you to chain indefinitely:

>> [a b]: [c d]: pack [1 2]
== ~['1 '2]~  ; anti

>> a
== 1

>> b
== 2

>> c
== 1

>> d
== 2

Though it feels a little bit unsettling when you drop it down:

>> [a b]: [c]: pack [1 2]
== ~['1 '2]~  ; anti

>> a
== 1

>> b
== 2

>> c
== 1

But we could argue that if you're bothered, then you use circling (currently @c, but with FENCE! proposed to be {c}). Note in the below example you'd have to use /b in order to indicate you were okay with unpacking more values than available.

>> [a /b]: [{c}]: pack [1 2]
== 1

>> a
== 1

>> b
== ~null~  ; anti

>> c
== 1

We could then make a choice if a: was a synonym for [a]: or for [{a}]:

Most Recent Motivation For Thinking About This

I rewrote some code in an example from this:

[^result' remainder]: parser input except e -> [
    remainder: input  ; succeed on parser fail but don't advance input
    return null
]
return unmeta result'  ; return successful parser result

...to this:

return [@ remainder]: parser input except [
    remainder: input  ; succeed on parser fail but don't advance input
    return null
]

The idea is that the parser being called has multiple return results... the first is the synthesized value, the second is the amount it advanced. (There's a third result on some parsers of "pending items", but this OPTIONAL combinator has an "autopipe" which is just bubbling the pending items through in the order of successful parsers called...so the third result is specialized out on its interface and on the parsers it calls.)

However, the synthesized value can itself be a pack. This means that if we named a variable in the slot where the @ is, then that pack would be decayed to store in the variable unless we used a ^META result.

So does the act of not-naming and just circling subvert the decay? Or should the circled result not be decayed even if the variable is?

>> [{a} b]: pack [pack [1 2] 3]
== ~['1 '2]~  ; anti  (or should it be decayed to 1?)

>> a
== 1

>> b
== 3

It's a different--but related--question. It seems it should align with the behavior of plain assignments:

>> a: pack [1 2]
== ~['1 '2]~  ; anti  (implied if the above behavior is chosen)

>> a
== 1

Not 100% Certain, But I Think Undecayed Propagation Is Good

I'll point out that it's possible to DECAY things pretty easily, but you can't recover a pack after it has been decayed.

So I'm getting the feeling that it's probably best to decay the assignments, but propagate the undecayed pack. It looks like the more general and useful behavior...even if it seems a bit confusing.

2 Likes