Retaking ++ and -- : how to get the old functionality?

The desire to turn -- into a form of comment, joins some of the spirit of wanting to take == away from strict equality. And we've even been discussing if there's something about ++ that makes its variants seem more like "drawing lines out of symbols" than really what Rebol wants to canonize as a somewhat niche operator.

This leaves us with the question of how to increment or decrement variables without having to mention their name twice:

number-of-variants: number-of-variants + 1

For historical perspective, Rebol did this with ++ number-of-variants...though it was a late and controversial addition, in 2007. That might make sense to a C programmer, but it doesn't really have any semiotic basis in Rebol lore. One thing is that it's not totally clear that something is getting assigned. Another problem is that you don't really get a way to increment by anything besides 1.

Ren-C gained the ability to quote left hand sides, so we tried number-of-variants: ++ 1. It was a step up, and permitted modifications by values other than 1.

But, we now want number-of-variants: -- 1 to make the 1 a comment. So another solution is needed.

number-of-variants: += 1 has seemed sort of even lamer than ++, given that = is not used for assignment at all. It is familiar, however, and should be mentioned as a possibility. And it might not be so bad: x: -= 1 might be read as "alter x such that it is equal to 1 less than it is now" as opposed to seeing the = as being there because it's an assignment operator...after all, you have the X: to suggest assignment.

In any case, we could make an operator that's generic in this sense. So number-of-variants: op + 1, the OP would quote the SET-WORD! on the left, fetch its value, then quote the right to get a FUNCTION!. It would make the fetched value the first argument...evaluating afterward to get the second argument. It's hard to give this thing a good short English name... I suggested me, as in number-of-variants: me + 1. Odd, but a symbolic name would kind of start chipping away at Rebol's aesthetic.

(I whimsically suggested a variant to use with prefix functions as being MY, so block: my append [1 2 3] would act as block: append block [1 2 3])

But while a very useful tool, ME and MY are suboptimal names. We might wonder if we can do better. One thing that's not completely out of the question would be just e.g. number-of-variants: - 1. It looks a little bit close to number-of-variants: -1, but Rebol is a language of space significance and that's something people have to live with anyway. Here's a sample broken implementation of the + operator that does this:

+: enfix function [:a [<end> any-value!] b [any-value! <...>]] [
    case [
        maybe [set-word! set-path!] :a [ ;-- `x: + 10` => `x: x + 10`
            set a add (get a) (take b)
        set? 'a [ ;-- `x + y` => `add x y`
            add (reduce :a) (take b)
    ] else [ ;-- nothing on left, switch to variadic sum
        sum: 0
        while [not tail? b] [
            sum: add sum (take b)

It looks promising when you try it:

>> 10 + 20
== 30

>> x: 10
>> x: + 20
== 30

>> x
== 30

>> (+ 10 20 30)
== 60

The only problem with it is that it has two competing demands on it when interacting with other infix math ops. When you write 2 * 3 + 4, Rebol's rule of precedence is such that the 2 * 3 must be evaluated before the addition. Yet since we're accomplishing our trick with quoting the left, it's not currently possible to defer to decide if we want to quote the SET-WORD! or not. A left quote can't be delayed on enfix, so you get the 3... not the evaluative 6.

But due to the state of the evaluator at that moment, it's not impossible. It's just something the evaluator needs to be modified to allow. Basically, to say that you're interested in SET-WORD! or SET-PATH! but only if they're literally there on the left, otherwise acquire the parameter as normal. We might call these <set> annotated parameters, the way you might say <end> or <opt>.

Is it worth it? I don't know. Every little piece of complexity like this is a tradeoff. And looking at x: - 1 meaning "subtract one from x" may not actually be that great. The average reader would assume that if it meant anything besides an error, it meant "make x negative 1".

Just putting it all out there to summarize the current state of things and see if anyone has any better ideas. I might go ahead and write me and my just so they're around in case someone comes up with a better name for them.

The more I think, the more I start feeling well with x: me + 1...
Yet another idea: x: <+ 1 :confused:

While @rgchris would prefer TAG! to own much of the space for interesting tricks (dialect [<+foo this is some="tag"+>]) I'm of the mind that we need things like <+ and <- for symbolic operators, and we don't necessarily want to go all in on HTML beyond the standard. It's good to have some nice tricks with HTML, but I don't want to bow to it at the cost of the rest of the language.

(The exemption of <!-- comment --> is still on the table, but I would still prefer to avoid it myself, all things being equal.)

But that said, I don't think <- 10 would be well used for "subtract 10 from the left." So <+ 10 would also seem odd for that.

I do think we're thinking about more tag-looking things actually being WORD!s, for operator use. That's kind of Haskelly. So <*> and <+> and the like might be better operators than tags... we already have history with <>. Hence if tags stuck to having a "starts with text" rule, we might go that direction.

The consideration of using -- for comments is being backed down from. Giving up -- for decrementing isn't too big a loss. But it would be too error-prone and visually dissonant to allow --foo or foo-- or --foo-- as words if it were pervasive in comments...and that has wider ramifications.

(Not so much because of the usage in Red's test suite...which we would like to have a driver for running. But I mention at least one major Achilles Heel brought about from outside the Rebolverse: the prevalence of --options on the command line in shell scripting space, an important domain for Rebol.)

But that said, I think this discussion still stands. -- as an operator which doesn't have anything to do with "separation", but carrying over C heritage meaning decrement "runs against the grain of what we feel it looks like". Same for ++. And now we're back to talking about // being comment, so if we tried to make this be some kind of pattern, it wouldn't be "divide-by" as part of the family. (I might say the same for ** as well, EXP is pretty decent for exponentiation when it comes up.)

So I suggest we continue along the line of thinking that these be applied toward their visual line-drawing-ish nature, and find some other way to do things like decrementation.

How about this idea ...

xxx: {+} 10
xxx: {-} 10

I call it the holy increment / decrement operators. The operator's sign stands in the middle and on each side the curly brackets represents it arms. It points to xxx and asks it to come forward. It points to 10 and asks it to do the same. They join in communion and become one body, one spirit. :wink:

This might be possible with <+> and <-> if those were to become WORD!s. It's up for debate...after all, <> isn't the empty TAG! even if it looks like it. One can imagine fanciful things like <!>: :breakpoint, which could be cool.

(Note: the debugger is broken and needs a bit of patching after a recent console shakeup, don't try to use it right this moment.)

But {+} and {-} are not expected to be anything but STRING!s. And strings aren't intended to become evaluator-active (even if they are capable of having bindings, as ISSUE!s are at this moment). There'd simply be nowhere to dispatch the behavior in that example to do anything other than assign a string to xxx, and then continue evaluating to the 10.

I'm feeling pretty comfortable personally with xxx: me + 10 at the moment, the only problem is we don't quite have the means to write that (yet!) Thinking about how exactly to do it.

Ahh right, strings! I knew it looked familiar, but it was getting late and I missed that.

I do like <+>, if we were to go down that route... and me is starting to grow on me too.

I am reconciled to a somewhat less greedy tags—would advocate for the most common HTML/XML markup constructs:

<tag with="stuff">
<tag />
    over="multiple lines">
<!-- Comment Tag -->
    Comment Tag
<!DOCTYPE tag>
<?process tag="1.0"?>

... and perhaps ...


Well, in the intervening years with new tech and revelations, I am reconciled to relinquish much of the space of WORD!-ish operators involving < and >.

One of the key driving realizations of "the power of TAG!" was motivated by something you did not like...which was my usage of <*> in tagged compose. It's not meant to be anything special, it could just as well have been <substitute-here>. But being able to have this inert type drawn out of thin air that has no evaluative meaning helped visually call out the places substitutions were happening.

That contrasts with my experience after clocking some time with Haskell. I've didn't end up as enamored with using operators like <*> or <$> vs words. I may still be envious of what the language does with these functions. But I think it's better when you can use these as structural markers for callouts that are specific to the code you are writing.

But a linchpin of being ready to lay down the limits was concluding that the only bindable "operators" with / in them are /, //, ///, etc. They present as PATH!s with BLANK!s in them, yet operate with the binding, storage characteristics, and behavior of a single aliased word. I believe this compromise is The Final Answer...and it will apply to ., .., ... etc. as well with a TUPLE! mechanic.

That same pattern can be used to solve the <> as TAG! and not-equal at the same time. Pretty awesome.

Furthermore...after working on making UTF-8 work well and compactly, it kind of seems a waste if nobody uses it. There's a bunch of arrows and symbols in there for anyone who has a special domain to attack, and feels stifled by the lack of operators. Install a keyboard mapping and use all the symbols you want.

The WORD!s with < and > Vision Statement

Here goes...

A WORD! which contains one or more > or < in it is referred to as an "arrow".

  • Arrows may start with < or end with >, but cannot do both.

    • Anything which does both is a TAG!, including <> (which has special-case mechanics allowing it to be uniquely executable, while tags with content will never execute)
  • All characters in an arrow (besides < and >) must come from a limited set of 4 other choices: =, -, +, and |.

    • These four are chosen for having a "liney" property making them suitable in drawing vertically symmetrical arrow-like things.

    • + as a cross is more complex than the "lines", but as a natural partner to - it seems weird to leave it out. You could more laboriously make a cross with <-|- that looks nicer as <+.

    • Underscore is excluded, despite liney-ness and symmetry, because it's on the baseline and doesn't make anything good. <__

  • Only ASCII is considered, as higher codepoint unicode constructions basically can draw whatever they want already.

  • ~ is reserved as a possibility for future use

    • It has a wave in it and is thus is not vertically symmetrical and a little "unclean", plus a little hard to distinguish between <- and <~

    • It's not clear if ~ is necessarily even best used as a WORD! character at all.

Having a "story" is important for holding things in your mind. So the realization is that we're looking to draw nice symmetrical arrows, not make symbol soup, and using ASCII only. We can thus give HTML back its ugly <!-- and feel nothing of value was lost. We don't mourn the loss of <&* or other things of that nature, because that wasn't what we were going for here.

This gives everything I'd want, including basics non-negotiables like >>= and |>, as well as >< which I've become attached to. Like I say, I'm considering the loss of things like <$> or <*> a feature and not a bug. These are fun new labels you can use wherever tags are honored.

With <> the only executable tag-looking thing, this sacrifices something becoming popular in many languages which is <=>. They call it the "spaceship operator"...doing a comparison of two values and returning one of three states (equal, greater, lesser) in a single operation.

But no big loss. Call it >=< and problem solved.

switch a >=< b [
    '= [print "A equal to B""]
    '> [print "A greater than B"]
    '< [print "A less tan B"]

The rules also allow a lot of things I'd probably not use. But some people like making fish ><>, and maybe long arrows have a point for someone =>=>>-. It's not contentious with tags, and it seems not worth the time or rule complexity to come up with ways of prohibiting it. We can't stop people from calling variables asldj323fjslsdf333ajsd-_-asdfafaa33afj either.

On the tag side, this permits a lot of ugliness. You can make ugly strings too. I guess I'm not really concerned about that...and just ask not to use <~ tildes ~> in case they wind up being desired in the arrows set. (My main reluctance to include it now is because I'm a bit reluctant about tildes in WORD! at all, and am wondering if they have some higher application...thinking on it.)

@rgchris can be the tag czar and cut down on problematic tags. Maybe experience would draw out what those are. Either way, things taken away from tag won't expand the set of things that are "legal arrow words".

What About HTML Comments?

The rules means <!-- isn't a WORD!, but --> is. Now when we look at:

     a comment
     that spans a bunch of lines
 -->   ; what are we looking at on the left, exactly?

I'd be comfortable letting this slide. Also, I'll mention that if you want to annotate --> as unambiguously a WORD! that you're executing or fetching, there's a new power in the toolbox:

-->/   ; terminal path means thing on the left is a function, run it
-->.   ; terminal tuple means thing on the left is not a function, fetch it

I don't think anyone would care, but... it's there. The main point of "moving on" is just being willing to release <!-- from consideration. A lot of being more comfortable with that is being fully comfortable with <!> as not executable when <> is executable.

Anyway, this proposal should cover everything, and I'm feeling pretty satisfied with it.

What Tags Are Ruled Out?

<- This isn't a tag ->
<-But this is->

<& This is a tag &>
<|and so is this|>
<|this is also a tag |>
<|>  ; this too
<& | >  ; and this
<| But this isn't |>

<<this is a tag>>
<< but this isn't >>

<++ this isn't a tag >
<++but this is >

Space rules are really the big issue here, but it's not clear what help you're doing by prohibiting a space before the closing of a tag on the same line if you allow multi-line tags. But... like I say... not really something I feel compelled to worry about too much. Just good to have everything in word space basically pinned down.

The more I look at this, the more I think that tag-looking-things that are only arrow characters being words is not that bad, and likely the only sane way for the mind to accept <> being a WORD!

This would bring <=>, <+>, <->, <|> and all of their friends (<+->, <-=->) into the arrows-fold. The spaceship operator could do what it does in other languages:

switch a <=> b [
    '= [print "A equal to B""]
    '> [print "A greater than B"]
    '< [print "A less tan B"]

Perhaps <-> could be SWAP (which I've been thinking could be extended to words. They'd have to be quoted if so:

>> a: 10
>> b: 20
>> 'a <-> 'b
== 20  ; !!! or 10, or void?
>> a
== 20
>> b
== 10

Maybe <+> could be an infix joining operator, maybe for newpath:

>> filename: 'README
>> extension: "txt"
>> %/some/path <+> [/ filename.(extension)]  ; dialected handling of TUPLE and /
== %/some/path/README.txt

Whatever <|> did, it should probably relate to expression barriers somehow.

Giving these meaning could help normalize the reflex people have in looking at them, and knowing the rules for arrow-words and not "seeing" a TAG!


Does this leave open the potential of <<, >> and >>> being used for shifting?

In a dialect like BITWISE, if we figure it out, yes.

But I do not believe bit fiddly math is relevant across enough domains to make it a great choice as a default.