GET-BLOCK!, GET, and REDUCE

R3-Alpha had what I had thought was a bizarre behavior:

r3-alpha>> get 5 + 5
== 10

If something wasn't a WORD! or PATH! it would fall through. Unless it was an OBJECT!, in which case it would get the values of the object vs. the OBJECT! itself.

Then it could SET a block, but it didn't symmetrically GET one...the BLOCK! was just one of the miscellaneous things that fell out:

 r3-alpha>> set [x y] [10 20]
 == [10 20]

 r3-alpha>> reduce [x y]
 == [10 20]

 r3-alpha>> get [x y]
 == [x y]  ; one of the as-is types, Red/Rebol2 error on this

I realized that if GET of a BLOCK! worked, then the GET of an OBJECT! behavior could just be get words of obj, which seemed more clear and generalized. So I changed GET of a BLOCK! to work symmetrically to set.

 ren-c>> x: 10

 ren-c>> y: 20

 ren-c>> get [x y]
 == [10 20]

And then along came GET-BLOCK! and SET-BLOCK!

The most sensible seeming behavior for :[...whatever...] would seem to be the same as get [...whatever...]. So at first I decided a shorthand for REDUCE was likely more useful. It seems you want to REDUCE blocks more often than you GET them (which is especially true since Redbol couldn't GET blocks at all).

But this raised a question: should GET of a BLOCK! reduce it? If R3-Alpha's odd behavior of letting you GET inert quantities was preserved you'd be almost there.

r3-alpha>> get 5 + 5
== 10  ; the weird behavior mentioned before

>> get [x y 5 + 5]
== [10 20 10]  ; potential extension of this

On the surface this would seem to offer an advantage of a shorter word than REDUCE, along with a symmetry between GET-BLOCK! and GET of a BLOCK!. But the symmetries break down because you expect GET of a WORD! that looks up to a function to give you the function back by value and not apply it. :frowning:

>> get 'add
== #[action! ...]

>> :add
== #[action]

>> get [add]
** Error: ADD is missing its value1 argument   ; uh oh

This was the reason that GET-BLOCK! behavior was changed away from REDUCE. Which I forgot when writing up my idea last night.

Alternate ideas?

Even if GET of a word looking up to an ACTION! gives an action directly, one could allow GET of a GROUP!:

 >> get '(add 1 2)
 == 3

 >> get [add (add 1 2)]
 == [#[action! ...] 3]

This could mean a GET-BLOCK! could be almost as powerful as REDUCE. It's just that REDUCE wouldn't need parentheses around function calls. But having something that's almost-reduce-but-not-quite might just be asking for trouble, and having the weird get 5 + 5 working could just be a slippery slope of luring people into misunderstandings.

I think it's kind of non-negotiable psychologically for GET of a BLOCK! to do the same thing as a GET-BLOCK!. Allowing that to be REDUCE seems to pack some power, but it would mess with things like:

set words of obj1 get words of obj2

If any of those words were functions, you'd wind up running them.

Hmmm.

It turns out it hadn't actually been changed yet, just written up that it should be changed to match GET of a BLOCK!.

But I'm questioning this assumption. Having :[x + 1 y * 2] act as reduce [x + 1 y * 2] seems much more useful.

I'm not sure how to reconcile this with not wanting GET of a BLOCK! to be a REDUCE. :-/ Rebol2, R3-Alpha, and Red all have no behavior for trying to get a block...it's an error. Maybe it's worth it to keep it that way so that there isn't a flagrant inconsistency?

I've also suggested higher purposes in the evaluator for SET-BLOCK!, for multiple return values. Hmm.

1 Like

My "suggested higher purposes" won out, and I'm pretty psyched about it.

To me this clinches the idea that :[what ever] does not need to mean the same thing as get [what ever] (if that means anything at all). As with the idea of doing element-wise assignment via something other than SET (e.g. ASSIGN), there could be some other analogous thing. (It's kind of like a form of REDUCE that just refuses to run functions... a kind of REDUCE/ONLY or REDUCE/SAFE?)

In fact... what if the old notion of "GET BLOCK!" is instead just a parameterized COPY that does an GET on each position? Avoiding the fact that there's no good syntax for "predicates" yet, imagine being able to provide an arbitrary function that transforms each item during a COPY?

 >> copy /negate [1 -2]
 == [-1 2]

 >> x: 10
 >> y: 20

 >> copy /get [x y]
 == [10 20]

Though you can imagine predicates that wanted to operate by position ("like a FORALL") as opposed to one item at a time ("like a FOREACH"). Perhaps that could be the difference between COPY and REDUCE, in that REDUCE has the ability to give you a smaller set of things than you started with?

>> reduce /(p => [p/1 > p/2]) [1 2 4 3]  ; 4 items
== [#[true] #[false]]  ; 2 items

Regardless of the specifics of these decisions I think the win of having :[...] mean REDUCE is very high. Having accepted multiple return values for [...]: instead of member-wise assignment clears up the concern I mention in this thread; it's not worth worrying about, there are better answers.

The most useful variant of REDUCE for this meaning is likely one where NULLs vanish, as opposed to turning into BLANK! or VOID! in order to not have extra slots. Getting the other variation might be reduce /try [...]


So long as we are on the subject, think about how you'd feel if code said copy .get [x y] or reduce .try [...] instead. Too subtle, or "just right?"

1 Like

.get is more in line with something you'd see in JavaScript-- not that that's prima facie a bad thing. A /path notation is more Rebolish, and more visible on the line. Forgive my heresy, but if you have any desire to make JavaScript devs feel at home with Ren-C, I think adopting the dot path notation is relatively harmless syntax sugar. I've thought about trying to make dot-paths in dialects to make the syntax closer to other languages I'm trying to mimic, but it's a hassle.

My concept for the reimagining of TUPLE! is to share code almost entirely with PATH!, and have basically all the same rules...a semi-generic array type which is immutable and requires at least two elements (even if one is blank), etc. Hence .foo would be using the same compaction method to make it no more expensive than a WORD!

Tuples would be fully inert, so the evaluator would leave them alone in normal evaluation. Which isn't to say they might not be useful for something...like passing parameters directly to refinements.

>> append/dup.3 [a b c] 'd
== [a b c d d d]

As with "no PATH! in PATH!" (at the top level array) being one of the enforced rules, there would be "no TUPLE! in TUPLE!". But further, "no PATH! in TUPLE!". e.g. the priority would be:

>> as block! 'foo/x.y/bar
== [foo x.y bar]  ; not [foo/x y/bar]

That makes sense, as you would expect people to want /usr/local/my-dir.dir/my-file.txt to be interpreted in a way that bound the tuples together.

It rolls around in my mind, with the various thoughts. One thought that I'm not concerned about is the loss of periods as WORD! elements, and I'm not terribly troubled by that.

More problematic is that things like 1.2 are historically decimal numbers in much of the English-speaking-programming-world. Not everyone would be thrilled seeing that have to be 1,2 or $1.2 or to decimal! 1.2 (dec 1.2?)...or whatever compromise was used to push decimal numbers out of the limelight. A math-oriented dialect could be willing to treat TUPLE!s decimals, I don't know.

Anyway, if TUPLE!s require at least 3 elements you get out of this trap...but that throws a wrench into filename.ext -- so I kind of would rather keep tuples pure and go with the comma notation (popular in enough countries to say it's learnable?)

What I like about this idea is that it frees up PATH! with leading-slash to be able to have an evaluative meaning. I'm not entirely sure what /something would do, but it wouldn't hurt to have an option. This would clearly be Redbol-breaking without an evaluator override, but you do have the option of quote /something when writing Redbol code that wants to bend to run in either.

If PATH! is fully known to be an evaluative entity, it cannot be used for these predicates*, because you confuse fetching paths with passing parameters. So that's why I keep thinking about this.

I'm wondering if entire countries can surrender the decimal point in their numbers and use commas, maybe a programming language can too. This would be Redbol-compatible, as Rebol has always supported it. Maybe it was a sign. :slight_smile: