Overall, I have been tremendously happy with how the ideas of the Big Alien Proposal have worked out.
That started from the concept that when slashes appear, they either come before a function they run, or after a function they suppress execution for.
foo.bar
; ^-- foo is an entity from which BAR is being selected. BAR is not
; allowed to be an antiform frame, so this syntax cannot invoke a
; function call (though it can invoke an 'accessor', e.g. a "getter"
; which is 0-arity).
foo/bar
; ^-- foo is an entity from which BAR (a FRAME! or antiform FRAME!)
; is being selected and then invoked. This will generate an error if
; bar is not a frame or antiform frame.
foo.bar/
; ^-- bar is a field which is an antiform FRAME!, whose execution is
; being suppressed. This expression will return an antiform frame, or
; an error if not an antiform frame.
foo
; ^-- conventional WORD! reference, will run an antiform frame as an
; action invocation or fetch other values as-is
/foo
; ^-- invocation reference, will run an antiform frame (or plain frame)
; as an action invocation and give errors on other types
foo/
; ^-- action suppression, will give you back an antiform frame as-is
; and error on other types.
(If you're curious about why /foo will run plain FRAME! as well as antiform, while foo/ will not return an antiform frame for plain FRAME!, this is based on the idea that it's better to be conservative when fetching values so that you won't get surprised by getting a plain frame back from ^foo which gives everything back as-is.)
I've written elsewhere how pleased I am that the way you suppress a function's execution is by throwing up a "barrier" with a separating slash that makes it clear arguments are not being gathered at the callsite. That's really slick.
For this idea to work, something else had to be used for refinements. That meant invention of the CHAIN! datatype has opened a lot of interesting doors, and I find it's quite learnable to see things like trim:auto:tail instead of trim/auto/tail.
I actually prefer it! What some might think of a disadvantage of being "less noticeable" turns into an advantage... trim:auto really could have been a function called trim-auto just as easily. Why would you want a slash to make the fact that it has a refinement "pop"? The slashes to make function calls or suppression pop are much better applied.
So that's all good.
No regrets!
But... requiring /FOO: For Action Assigns Hasn't Gel'd
Another part of the proposal was that in order to get tighter control on what was a function or not, you would be required to assign functions using a leading-slash kind of SET-WORD!.
>> foo: func [a b] [return a + b]
** Error: FOO: can't be used to assign antiform FRAME!, use /FOO:
>> /foo: func [a b] [return a + b]
== ~#[frame! "foo" [a b]]]~ ; anti
It hasn't settled with me after working with it for some time.
As I mentioned above, colons for refinements was easy to adapt to...and now that I'm adapted, I prefer it. But I'm kind of cursing under my breath the thought of having typed test: and having to backspace over it so it says /test:. And then I go "hrmph."
It's certainly nice to have a shorthand for foo: ensure action! ... and so I don't think the feature should be thrown out. It helps make things clearer to say "this is an action assignment" in a nice and light way.
But when you're writing foo: func [...] [...] you already know it's an action, and being forced to say you do makes the code look junky. It's a burden in a way the other changes are not. It's the only change that increases the character count.
If it can't settle with me, it will definitely put others off, and lose a major aspect of the clean feeling of the language.
What's At Stake By Not Enforcing This?
Ren-C has a powerful story about how antiforms can't be put in blocks, which means you can write this kind of code and it "just works":
block2: collect [
for-each 'item block1 [keep item]
]
assert [equal? block1 block2]
When you compare it to Rebol2/R3-Alpha/Red, it's one of those vastly superior situations. You aren't getting tricked into receiving an ITEM in the FOR-EACH that would generate an unset variable error, or conflate with the state that gets returned when an item can't be picked from a block, or accidentally run a function. It's a solid solution.
But that's only for blocks. What about other places, like objects?
If we don't put barriers on how action antiforms get assigned to variables, we get the problem all over again:
for-each [key value] obj [
if integer? value [ ; oops, what if VALUE is an action antiform!
print "Found an integer"
]
]
There's no way in this case to say "variables can't hold antiforms". Logic is an antiform. Words holding antiform frames are actions.
Getting this under control with slashes is the kind of thing I've been trying to do for a long time, I've just never had the syntax. Leading slashes felt like it could be the key:
for-each [key value] obj [...] ; value can't be frame antiform
for-each [key /value] obj [...] ; value must be frame antiform
for-each [key ^value] obj [...] ; value may be anything whatsoever
But if these rules are applied everywhere, what you have to do gets more complex:
set $x does [print "Is this an error?"]
set $/x does [print "Do you have to do this?"]
>> var: $x
== x ; bound
set var does [print "If this errors, how to make VAR into bound /x?"]
set:active var does [print "Do you use refinements?"] (or just SET:ANY ?)
Nothing is free. And the already more complicated world where x: is a CHAIN! instead of a fundamental different type of word has its own issues, that these all pile on top of.