Shove left (<-), shove right (->), left bar (<|), right bar (|>)


#1

SHOVE came into existence because there was no feasible way to dispatch infix automatically from paths. LEFT SHOVE now gives you the same behavior you would get if an infix operation had dispatched:

>> add 1 2 * 3
== 7

>> add 1 2 <- lib/* 3
== 7

Not only can you now run enfixed functions out of objects, but you can invoke refinements on infix arguments. It's even smart enough to pick up on the quoting convention of the right hand side:

>> x: null

>> x: <- lib/default [1 + 2]
== 3

>> x
== 3

It doesn't even matter if the thing on the right is enfixed or not, it will act like it was...just in case you felt like putting an argument to the left of something:

>> 1 + 2 <- lib/multiply 3
== 9

And since one of the many reasons for SHOVE existing is to avoid double-group evaluation in lookahead, note it has that covered:

>> 1 + 2 <- lib/(print "only prints once" first [*]) 3
only prints once
== 9

That's a lot of stuff to take in. But of course, who do you think you're talking to... of course there's more! :stuck_out_tongue:

Now there's a difference between <- and ->

Both are shove operators, but -> doesn't act like an infix operation happened when it runs the right.

>> if 10 = 5 + 5 [print "Classic error"]
** Script Error: + does not allow logic! for its value1 argument

>> if 10 <- = 5 + 5 [print "Error parity when using shove left"]
** Script Error: + does not allow logic! for its value1 argument

>> if 10 -> = 5 + 5 [print "But shove right has your back!"]
But shove right has your back!

Even though the right doesn't operate as infix, the left does. So if you have more than one thing to put on the left, you'll have to put it in a group:

>> (1 + 2) -> = 2 + 1
== true

But hey, at least it works, this used to be impossible!

 >> (1 + 2) = 2 + 1
** Script Error: + does not allow logic! for its value1 argument

Even more fun: RIGHT BAR |> is a "postponing shove"

In case you wanted to run all the stuff on the left...

 >> x: add 1 add 2 3 |> lib/* 4
 == 24

 >> x
 == 24

It still has to follow the rules of postponement, it has to be at a "full stop" position (e.g. anywhere an an expression barrier would be legal).

And for good measure: LEFT BAR is...some other thing

This may seem kind of random, but it's actually the only thing in this list that's meant the same thing since the symbol started being used. It's a postponing invisible evaluator. It acts as a barrier and evaluates to what was on its left, forgetting the right.

>> 1 + 2 <| print "Hi" x: 10 y: 20
Hi
== 3

>> x
== 10

>> y
== 20

People need to try these things out!

These aren't frivolous...they're very important. SHOVE was a solution to very real problems about needing to dispatch overloaded words from LIB, as well as some hypothetical-yet-interesting questions about being able to put refinements on infix.

But ponder this: being able to avoid parenthesization is very good when you want to save your GROUP!s for some other thing (like COMPOSE). So if you can clearly express yourself with just -> or <-, that's the same number of characters and you aren't sacrificing your groups.

I'd love to sit around imagining every possible test and edge case for these things, but I do not have time to do that and everything else. Try using them and tell me what happens!


#2

I assume this is a replacement to Rebol 2/3A's ALSO? Is there a textual equivalent?


#3

I don't see them as particularly related, outside of perhaps a tangential point of "in category of tools that might let you reorder your executions". This fills in completely missing features: before you couldn't call infix functions resident in paths, you couldn't call infix functions with refinements. ALSO wasn't involved in that at all.

ELIDE is more what I would point people to who were looking to do something ALSO-ish. So if you would write this in Rebol2:

rebol2>> also (print "First" x: 1 + 2) (print "Second" y: 10 + 20)
First
Second
== 3

rebol2>> x
== 3

rebol2>> y
== 30

You could do that in Ren-C with:

ren-c>> print "First" x: 1 + 2 elide (print "Second" y: 10 + 20)
First
Second
== 3

ren-c>> x
== 3

ren-c>> y
== 30

But ELIDE uses the general tool of invisibility, so you can make more constructs like it. For instance, ELIDE only elides one expression. If you want to avoid a GROUP!, the variadic <| decribed above feeds the right for you to the end:

ren-c>> print "First" x: 1 + 2 <| print "Second" y: 10 + 20
First
Second
== 3

>> print "First" x: 1 + 2 <| print "Second" y: 10 + 20
First
Second
== 3

>> x
== 3

>> y
== 30

Awwwwesome. :slight_smile:


#4

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


#5

I aim to impress myself, and I'm a very tough audience. :slight_smile: So hopefully that means something is being made here that will ultimately amaze many more people.

I want to move to some sort of solution where people can collectively edit--Wikipedia style--and that things can be improving in real time. It's going to take some critical mass... all help is appreciated...