Show the Love for SHOVE (>-)

>-

Despite having a bit tricky to implement, it's very easy to understand. It just pushes the argument on its left to be the first argument of the operation on its right:

>> 1 >- add 2 * 3
== 7  ; as if you'd written `add 1 2 * 3`

Simple, right? You might think it's not something you would use... but you'd be thinking wrong!

Invoke enfix functions in modules or libraries

Enfix execution cannot work with paths (this isn't a bug, it shouldn't work):

r3-alpha>> 1 lib/+ 2 * 3
** Script error: op! type is not allowed here

But shove has your back:

>> 1 >- lib/+ 2 * 3
== 9  ; as if you'd written `1 + 2 * 3`

(Note the result is different from what you get with add, since + is enfix.)

This is only going to get more critical as modules and namespacing move forward. And anyone who's redefined an operator--but wants to temporarily reach for another implementation--will want this.

Invoke refinements on enfix executions

Historically there aren't really refinements on infix functions, because you'd never be able to use them. Now you can:

>> ++: enfixed func [a b /double] [a + either double [2 * b] [b]]

>> 10 ++ 20
== 30

>> 10 >- ++/double 20
== 50

In the common case, you hope that your operator doesn't need refinements. But when a special case comes up, it's nice to not have to define a prefix form just for that one instance. (which means coming up with a new name that people need to know also). Now you can take for granted that shove is there when you need it.

Symbol-y, but not symbol soup: it communicates!

Being an "arrow word" is crucial to showing its disruption of the evaluation order. That's not going to be conveyed by a short alphabetic name:

>> 1 shove lib/+ 2 * 3   ; lame and wordy
== 9

Invoking enfix functions from modules/namespaces and using refinements with them is fundamental behavior. So it needs to be very short and light. You want people to take this thing for granted!

Extra credit: tweak the argument precedence

Rebol is well known for having a difference in interpretation when you use an infix operator vs. not:

>> add 1 2 * 3
== 7

>> 1 + 2 * 3
== 9

(If you don't know why that is--and wonder why such a "quirk" hasn't been changed despite a lot of thought--you can read more than you ever wanted to about it).

Above I showed that shove takes its cue on how to act based on the enfixedness of what you're shoving into:

>> 1 >- lib/add 2 * 3
== 7  ; as if you'd said `add 1 2 * 3`

>> 1 >- lib/+ 2 * 3
== 9  ; as if you'd said `1 + 2 * 3`

But it might be argued that since >- is enfix, the overall operation is always enfix, which intuitively would suggest both of the above should be 9.

It's tough to say. But I liked the simple definition of "shove uses the value on the left as the first argument". Imagine what the "as if you'd said" would have to be if the shove into ADD above gave 9, if you couldn't take for granted another known another name for the operation (like +):

>> 1 >- lib/add 2 * 3  ; let's say it's the hypothetical enfix-always version
== 9  ; as if you'd said `temp: enfixed :add | 1 temp 2 * 3`

But for sake of completeness...I introduced "force enfix behavior (->-)" and "force prefix behavior (>--)" forms:

>> 1 ->- lib/add 2 * 3
== 9  ; as if you'd said `1 + 2 * 3`

>> 1 >-- lib/+ 2 * 3
== 7  ; as if you'd said `add 1 2 * 3`

I think it's cute that ->- looks like a picture of args on the left and right of an operator, suggesting infix... while >-- looks like no args on the left with two args on the right!

But you could also just use parentheses:

>> (1 >- lib/add 2) * 3
== 9

>> 1 >- lib/+ (2 * 3)
== 7

So whether ->- and >-- survive or not is an open question. If anyone actually uses them, I'd be interested to know.

2 Likes

You always manage to amaze. The only downside is, that it gets harder and harder to keep track of all the new features.

1 Like