Bitten By Right Side Evaluation First

I was writing some code like this:

while [not tail? info] [
    if find leaders info.1.name [
        leader-protos.(info.1.name): take info
    ] else [
        info: next info
    ]
]

Due to the post title you probably already see the bug. TAKE INFO on the right hand side runs before the info.1.name. So it's inserting under the next name.

I think we can (and should) precalculate the groups on the left hand side. Basically walk the tuple and push its elements to the stack before doing the right hand side evaluation.

What if the RHS alters the index? Then the LHS could be left pointing to an unexpected element.

Some history: Rebol2 did not have the idea of allowing groups in paths.

You could put GET-WORD! in paths, and they would be looked up:

rebol2>> block: [a b c]
== [a b c]

rebol2>> index: 2
== 2

rebol2>> block/:index
== b

(Ren-C actually prohibited GET-WORD!s in paths, though interestingly the syntax is becoming legal again with CHAIN!...though it won't have anything to do with "getting")

But generally when you said block/index it took you literally:

rebol2>> block: [foo 10 index 20 bar 30]
== [foo 10 index 20 bar 30]

rebol2>> block/index
== 20

DocKimbel believes (or at least, at one time said) that adding GROUP!s*cough* :nauseated_face: PAREN!s into paths was a mistake because it complicated the model. I don't think it was a mistake, but it certainly did bring a lot of questions... including the order of evaluation questions.

Some stuff from way back:

Parenthesized expressions on left for SET-PATH! evaluate after right hand expressions · Issue #2275 · metaeducation/rebol-issues · GitHub

We can look at fundamental behaviors, like:

obj: some-obj
obj.field: (obj: some-other-obj, 20)

You might argue that you need to lookup OBJ to the instance of the object it resolves to and remember that, before running the right hand side which disrupts it. That is technically possible for objects...but if you resolve "immediate" values like TIME! or DATE! and forget the variable that held the immediate, they can't write back to them...due to the fact that all the bits for those types live in the cell, so there's no abstract "address" to resolve to. The closest thing you have to an address is the name of the variable, and then you're back to lookup semantics again.

Anyway, the easier bit to do is to resolve the left hand side groups. But if the left hand side is fully resolved in a way the right hand side can't disrupt, that involves some sacrifices on immediate writeback that are probably not worth making, in the grand scheme of things.