So I've decided that terminal slash has the best application as fetching an antiform action without running it.
This is a very commonly needed thing, and representing it with a slash at the end offers the dual benefit of saying "this is something dealing with function dispatch" (as slashes now are exclusively), but also to throw up a kind of barrier between the function and any potential arguments...to help reinforce that it doesn't take them.
for-next: specialize for-skip/ [skip: 1]
; ---^
; slash helps reinforce the block is not argument
Much nicer than using get $for-skip
, and you even have a typecheck built into it, like:
for-next: specialize (ensure [action?] get $for-skip) [skip: 1]
I've gone through and applied this and it's very good. A lot nicer than GET-WORD! ever was, and avoids the nasty conflation of tolerating unset variables as well as defusing actions...which I have always despised.
red>> type? :append
== action!
red>> type? :asdfasdf
== unset!
Terminal slash has one job: give you back an antiform action as-is...and if it isn't one, error.
So all right, leading slashes should probably mean function call always, when not used in an assignment.
But assignments are tricky. I feel this much is firmed up:
value: ... ; can't assign an action
/value: ... ; might assign an action
value/: ... ; must assign an action
It would seem that /value/:
is inherently contradictory. Happy to rule it out for now.
Think we know this for a fact:
obj.field: ... ; can't assign an action
I think this would suggest for the pattern that prefix slash used with tuple might assign an action:
/obj.field: ... ; might assign an action
And for consistency, I think it is best to say terminal slash on a tuple acts as it would on a word:
obj.field/: ... ; must assign an action
Then we can rule out /obj.field/:
as meaningless.
Then we have the 4 internal slash cases for obj+field. For the sake of brevity, I think obj/field
should be a synonym for obj.field/
... one less character
obj/field: ... ; must assign an action
As for the stragglers... hm. I dunno.
/obj/field: ... ; ???
obj/field/: ... ; ???
/obj/field/: ... ; ???
Conservatively rule them all out for now, I suppose.
One Gap: Run Sequence If Function, As-Is-If-Not
So WORD! has the fuzzy ability to run it things if they are functions, or give the value as is if not (or error if it's a tripwire or nothing).
But if your value is in a context and needs to be selected out of it, the current model forces you to pick either path (run it) or tuple (get as is).
I don't want to relax the tuple rule. It's way too easy to mess up and say obj.method
and have it fetch inertly and throw everything off. At minimum you should have to say obj.method.
to get that. And I don't want plain obj.method
to be willing to invoke actions, because that loses the whole advantage of this strategy.
It's probably not wise to have this conflation except for arity-0 functions (how would you meaningfully handle something that sometimes consumed arguments and sometimes didn't?) And if it's an arity-0 function where you want it to act like a value, maybe that's a job for accessor.
It's something to keep an eye on, but I guess I'd like to see the motivating examples before trying to solve it.