Dialecting Function Calls: New, Weird, Powerful

One of the reasons for dropping slashes for refinements was a belief that it served better as a function call indicator.

And I think that has turned out to be very true. It's a better world, with clearer source:

obj.field  ; fetch member (ACTION! not allowed)

obj/method          ; run ACTION! (slash before: function is thing after slash
obj/method:refine   ; run ACTION! with refinement

obj.method/  ; fetch ACTION! (in "action-pack" form, for no-warning assignment)

^obj.whatever  ; meta-fetch (can be anything, given back as-is)

/word  ; dispatch function from word, error if not an ACTION!
word/  ; fetch ACTION (in "action-pack" form)

/obj.method  ; another way of running methods (probably?)

So it's worth mentioning:

Once you allow slashes in more places than the above, you're dropping the terra-firma that "if you see a slash, that means a function call...where the thing on the left is a container in which that function was found."

So here we see an anchor being lost: we no longer know by inspection that REDUCE is not an object, with a function member OPT.

Sure, we can argue it's not actually that bad. Because had it been a bare word, you would have had to have known whether REDUCE was a function or not.

If you see:

foo.reduce/opt [1 + 2 null 100 + 200]

Then you know REDUCE isn't a function. And if you see:

foo/reduce/opt [1 + 2 null 100 + 200]

Then you know REDUCE is a function.

One unsettling thing might be that to say that if you buy into this line of argument, it was never necessary to change slashes from meaning refinements in the first place.

In this view, the only "important" separation was the TUPLE! vs. PATH! change. From that, you could infer everything you need to know.

:grimacing:

I Don't Know, I Like CHAIN! And :REFINE, But Still...

Perhaps some amount of fluidity would help in terms of the "dialected function call" notion.

For example, what if that's what leading slash meant in the spec... optional parameter, that if you use a slash, it fills it in?

>> foo: func [x [block!] :y [integer!] /z [tag!]] [
       probe x
       probe y
       probe z
   ]

>> foo/<*> [a b c]
[a b c]
\~null~\  ; antiform
<*>

>> foo:y/<*> [a b c] 1020
[a b c]
1020
<*>

>> foo:y:z [a b c] 1020 <*>
[a b c]
1020
<*>

This would mean it would be compose/{} instead of compose:{} in order to make a dialected call. CHAIN! would be used for specifying the refinement by WORD!, and paths would just slip the arguments in order for the dialected call.

If you had more than one they'd just go in order:

>> foo: func [x [block!] /y [integer!] /z [tag!]] [
       probe x
       probe y
       probe z
   ]

>> foo/2/<*> [a b c]
[a b c]
2
<*>

That's Kind Of Unhinged, But Outrageously Practical

It's so useful and ergonomic that now that I see it, I kind of can't imagine not doing it this way.

Going by position in the function spec (vs. having any kind of weird magical "We pass you the chain and you process it") strips this down to its essence. A cheap, clear, fast mechanic.

We might discourage using WORD! for anything besides functions, to help avoid writing ambiguous-looking things.

But one question would be "how do we go from WORD! to 'thing word looks up to'":

switch/typecheck value [
    integer! [
         print "it was an integer"
    ]
    [series? tag!] [
         print "it was a series or tag"
    ]
    ...
]

That /PREDICATE argument is presumably ACTION! or FRAME!. So this means you'd have to distinguish between @/predicate literal (or /@predicate ?) and /predicate, where it would fetch the variable for you.

(Note: @/predicate is cheaper at time of writing--there's an optimization for the Sigil being on top of the PATH!, but not underneath it...so it costs a non-trivial amount more to have /@predicate. I actually think separating with the slash is more readable, because the letters aren't jammed up against the @ sign.)

But that gives you the problem that /PATTERN for COMPOSE would be marked as being literal. But maybe it's only literal if you use it in the PATH!, and if you use COMPOSE:PATTERN it disregards the literal marker, because you're not using the / so it handles it more like an APPLY.

:exploding_head:

(I'll reiterate that this is not entirely new. Ren-C used slashes for predicates early on, by seeing patterns like any /even? [...] and assuming that meant you wanted EVEN? as the predicate. But this is that on steriods, and the implications are huge.)

1 Like