I think I may be building to The Answer. The watershed concept of tuple and path discernment could give what we need here.
Let's say we put it back, and then...
PATH! looks up ANY-VALUE!, but errors on VOID!. If the value that it looks up to is an ACTION!, it runs it.
...but new twist... if you end the PATH! in a slash, it will ensure the looked up to value is an action. If it's not, it will error.
If an action is executed, then all results are considered legal...so it can return ANY-VALUE!, including ACTION! and VOID!
We can observe thus that there is a policy that "nothing to the left of a slash can be void".
GET-PATH! is a variation on PATH! that does not run the action, but just fetches the value...and does not error on VOID!
- As with plain path, ending with a slash will enforce that the looked up result is an ACTION!. But since this is also the result, it further guarantees the overall evaluation is an action.
TUPLE! acts like PATH! with the distinction that nothing to the left of a dot can be an ACTION!.
If you end in a dot, you are thus saying that the result is neither an action or a void. You don't run the action, so you just got the value looked up to.
If you don't end in a dot, the result can be ANY-VALUE!, because you may run an action...and many actions return void.
GET-TUPLE! modifies tuple access rules to parallel GET-PATH!, but without the allowance of VOID! return results.
- A GET-TUPLE! that ends in a dot is thus pointless if you're writing it from scratch, but if it was fabricated by transformation it does the right thing.
So for day-to-day safety, tuples are the best choice: a.b.c. If you're paranoid about running code when you don't want to run code, end those tuples with dot (e.g. a.b.c.)
But this doesn't give you any particular super powers on the results of plain tuple. It would be neat to have a shorthand for checking a function invocation to say something about the results.
We could imagine it being an application of the leading position:
/some/path/ ; ensure an action is run, then ensure result is ACTION!
.some.path ; action may or may not run, result is not ACTION! or VOID!
That's fairly rational. But we need tuples with leading dots to be inert too badly (for predicates), and might as well stay compatible with history having "refinements" be inert too. Two good reasons to avoid such an interpretation.
There's adding more to the the trailing position, but it has a problem differentiating check result vs. check lookup. Only these two combinations have meaning:
some/path// ; ensure an action is run, then ensure result is ACTION!
some/path/. ; ensure an action is run, result is not ACTION! or VOID
You get a contradiction out of some.path./ ("guarantee lookup isn't a function but that the result is"). And some.path.. is useless ("guarantee lookup isn't a function and that the result isn't a function"). There's no point in introducing something broken and ugly, for only two cases that no one would use.
However, if you're target is an assignment vs. passing the value on somewhere...then as a consolation prize, we can use the terminal state on assignments in SET-PATH! and SET-TUPLE! by giving meaning to it:
Though that's only two options, they're pretty good ones to have. Almost all the the time you need to know whether you're assigning an action or not. And if you're assigning an action you know it's not void, so both these assignment forms prohibit voids.
It's weird to see it all bottoming out at baseline where x: :y is absolutely 100% permissive...any state on either side. But there's a kind of purity to that, and it's certainly good for code golf (which remains an important target market in my mind!)
I think as people adjust to using TUPLE! by default, the GET-TUPLE! protection against void will seem natural. And tools like ensure integer! x and non action! y are all shaping up pretty well to fill in the rest. Terminal dot and terminal slash are just convenient and effective shorthands for common worries, for people who have systemic needs for good error locality (e.g. me debugging bootstrap!)