In the corpus of code we have so far, it seems to me that when a refinement adds an argument to a function that it would be preferable if that argument would become the first parameter... not tacked onto the end.
Some cases might not be completely obvious one way or another:
>> append [a b c] [d e]
== [a b c [d e]]
>> append:dup [a b c] [d e] 2 ; old way
== [a b c [d e] [d e]]
>> append:dup 2 [a b c] [d e] ; new idea
== [a b c [d e] [d e]]
I think it's better if it's first, but it's not earth-shattering.
But in other cases it seems very much an improvement. Consider the positioning of the argument to FAIL:BLAME...
foo: func [arg thing] [
if arg < 0 [
fail:blame [
"Here is some long error message:" @thing
"Whatever..."
] $arg
]
]
foo: func [arg thing] [
if arg < 0 [
fail:blame $arg [
"Here is some long error message:" @thing
"Whatever..."
]
]
]
Or an argument to COMPOSE giving a pattern to use:
compose:pattern [
some bunch of {{code that}} <spans>
#multiple lines
[and could go on for pages]
] ${{}} ; afterthought...
compose:pattern ${{}} [ ; forethought
some bunch of {{code that}} <spans>
#multiple {{lines}}
[and could go on for pages]
]
This goes along with some Haskell philosophy I cited in Parameter Order in Rebol:
"It's common practice in Haskell to order function parameters so that parameters which "configure" an operation come first, and the "main thing being operated on" comes last. This is often counter intuitive coming from other languages, since it tends to mean you end up passing the "least important" information first. It's especially jarring coming from OO where the "main" argument is usually the object on which the method is being invoked, occurring so early in in the call that it's out of the parameter list entirely!"
These refinements typically seem to be configuring, as if they are changing the function itself, and belong at the head.
e.g. above, the function you're conceptually applying is (compose:pattern ${{}})
History Didn't Do It This Way, With Some Reasons
Refinements are typically listed at the end of the function spec.
From an implementation standpoint, that's also where their "slots" are in the argument list.
This means that as you are walking the argument list and fulfilling arguments from the callsite, if refinements were used you would have to skip over the "normal" arguments in a first pass, and then come back and fill them later.
Historical Redbols only had to be worried about the order of usage of refinements... if you used them out of order from the declaration, a second pass would be needed. But using them in order would not require it.
This isn't a problem for Ren-C...it's designed for generic parameter reordering (refinements or otherwise) and it has an efficient way to beeline back to slots it skipped on a second pass.
So really the only issue is the mismatch between the visual order in the spec (which may be exposed mechanically by fixed orders of enumeration of FRAME! keys and values), compared with the gathering behavior. But the disconnect of that order has always been there, with foo/refine1/refine2 vs. foo/refine2/refine1 in Redbol... the callsite order may not match the frame order.
Is It Worth Changing?
The competing (complementary) idea of CHAIN! dialecting offers something that's likely even more compelling:
compose:pattern ${{}} [ ; better than today...
some bunch of {{code that}} <spans>
#multiple {{lines}}
[and could go on for pages]
]
compose:${{}} [ ; ...but this surpasses even that
some bunch of {{code that}} <spans>
#multiple {{lines}}
[and could go on for pages]
]
Though it's kind of up in the air if and when that's going to get attacked, and how well it will work (it may run afoul of problems in binding, etc.)
My instincts tell me that it's worth changing. In practice, refinements that take arguments are not super common... but when they do happen, being up front seems to make the most sense.