Idea for Naming Function Arguments Out of the Way

#1

As part of Rebol's contention-for-short-names problem, there are many instances where refinements have names like /ALL where they conflict with common natives or lib functions.

When this happens, I tend to do something to name them out of the way and put the lib function back:

foo: function [
    bar [block!]
    /all "foo all the bars"
][
    all_FOO: all  ; !!! Note: this is proposed to become /all
    all: :lib/all
    ...
]

Clearly we need a better pattern. Something that occurred to me today was the idea of being able to name refinements in the spec via a longer path:

foo: function [
    bar [block!]
    /x/all "foo all the bars"
][
    ...
]

The concept would be that the interface to the user (e.g. HELP) would still just show /ALL. But you as the function author could clearly see that you were supposed to refer to the refinement as /X/ALL in the body of the function. And the binding of ALL would be left alone inside the function body to whatever it would typically be.

For performance, the name you pick in the path could be set up as an alias for the frame of the function itself. So if you probed the x above you would see it is a FRAME! with bar and all inside it. If you wanted to, you could call x something more meaningful like this, or if you aren't making recursive calls you could even name it foo

The same could apply to normal arguments, just with no leading slash:

foo: function [
    x/bar [block!]
    /x/all "foo all the bars"
][
    ...
]

So that would leave bar bound as-it-was in the body, vs. binding it to the bar argument.

1 Like
#2

Quoting from https://forum.rebol.info/t/quoting-decisions-in-practice-null-refinements/1166:
"Refinement-style-paths are like a GET-WORD! that's null-tolerant...they evaluate."

So wouldn't you be able to use /all everywhere you meant to use the refinement-valued all?
This would break a LOT of code, but, on the other hand, refinements now evaluate ...

#3

That wouldn't help with non-refinement parameters with names you didn't want to override...unless you decided to make every use of an argument null-tolerant.

Plus, I like not using the null tolerant form in places you've established the refinement was specified.

foo: function [/bar [integer!]] [
    bar: default [1 + 2]
    ... ; no need to use /bar here, you know it's set.
]

To me, one of the big benefits of the new distinction is letting you convey to the reader your state of confidence (or lack of confidence) of whether something is set. GET-WORD! didn't do that, because of its double meaning.

As I've said, I think this is kind of tying together to build sort of the best-case-scenario for the questions that plagued refinements and refinement arguments in the early establishment of null.
That was when tradeoffs were being looked at with how Rebol2 would make refinement arguments blank in a way that might lead to them being accidentally used improperly when the refinement was not specified. Trying to couple it so that a falsey refinement always forced the refinement arguments to null was not as good as this unification...it seems to tick all the boxes.