Historically, GET could not get a path:
rebol2>> obj: make object! [x: 10]
rebol2>> get 'obj/x
** Script Error: get expected word argument of type: any-word object none
That changed in R3-Alpha. Red followed suit:
r3-alpha/red>> get 'obj/x
== 10
Which seems like an improvement...but opened the door to something I've complained about: GET having side-effects, such as:
red>> path: 'obj/(print "Boo!" 'x)
== obj/(print "Boo!" 'x)
red>> get path
Boo!
== 10
When you say that two sequential GETs can get something completely different even when nothing has changed, that really pulls the rug out from under any generic code that wants to build upon what a GET is. Similar issues apply to SET.
How Do Pick and Poke Compare?
PICK and POKE add an extra parameter of a location to pick or poke from. But then they still have a "picker" of some kind.
This leads one to wonder if this would work, but it doesn't:
r3-alpha>> outer: make object! [inner: make object! [x: 10]]
r3-alpha>> pick outer 'inner/x
** Script error: pick does not allow object! for its aggregate argument
But there are two possible interpretations. If OUTER is something like a MAP, it could be looking up the PATH! inner/x as the key in the map. Or it could be looking up the key inner, fetching the thing in the map, and then picking x out of that.
MAP!s don't allow PATH! in R3-Alpha or Red, but if they did...we'd assume it would interpret inner/x as the key.
So Historical PICK and POKE are Strictly Less Powerful?
This makes it seem like GET and SET have the ability to do anything that a PATH! or SET-PATH! can do. But PICK and POKE can only go the last mile and ask one container about its response to one key.
Could we make a synonym for PICK, if we just GET a PATH! that we make up? Let's try that in Red:
red>> pick2: func [series index] [
get make path! reduce ['series to paren! reduce ['quote index]]
]
red>> m: make map! [a 10 b 20]
red>> pick2 m 'a
== 10
red>> b: [x 30 y 40]
red>> pick2 b 'y
== 40
It appears to work, but the issue is that I'm sure these are completely different code paths. So you'll see subtly different behaviors for PICK vs. pathing where they'll be the same most of the time, but then not.
It would only make sense to have two codebases if someone could articulate what's different about "picking" and "pathing". Outside of function call dispatch with refinements I can't think of a good argument for a difference. And Ren-C uses TUPLE! instead of PATH! for conventional picks, so the tuple-based picking could truly be the same.
Not Easy To Reason About
This is all made-up stuff with really imaginary semantics. And I've come up against the hard questions like trying to make this work:
item.(expression): default [...]
If you GET that SET-PATH! on the left to check to see if there's a value in it or not, and there isn't, then you decide to run the right hand side. Then you want to SET the SET-PATH! on the left...but without some alternate mechanism, you'll be evaluating the expression twice.
Being able to turn that item.(expression)
into some sort of reusable currency that you can GET and SET multiple times without side effects is ideal. Once this was done by COMPOSE'ing that PATH!, but paths are now more restrictive in what they can have as members...so it would have to be turned into a block.