Agree-To-Disagree Points: Places I See Both Sides

I thought I would make a thread for deviations from Rebol2 that I consider to be matters-of-taste, as opposed to where I think there's a hard "right vs. wrong", and provide the code to reverse the decision.

(Please discuss the issues on the linked posts--not here.)

Must RETURN from FUNCTION to get a result

If you do not explicitly RETURN a result from a FUNCTION you'll get a "~ isotope" (morally equivalent to an UNSET! in Rebol2).

My certainty about the core change hinges on the fact that our RETURN is a function that can be redefined and hooked (or defined not to be a function at all).

  1. I don't like having a hidden call to that function be there, just in the abstract. Makes me uneasy.

  2. Since people might want a hidden call or not want it, it's cleaner for the core have it not there. It's harder to erase its influence, than to simply add it if you want it.

  3. I'm just a bigger fan of explicitly pointing out that the last line of a function has a meaningful result for its callers, vs. having to guess.

    • Not that "just because JavaScript does something we should do it too", but, JavaScript also requires explicit return from a function--otherwise the result is undefined.

While 1 and 3 are kind of personal preference issues, 2 is a design point. The version that fabricates a function call at the end of the body is more complex than a version that doesn't, and we'd be implementing the latter in terms of the former no matter what. The only debate is on which one is called FUNC(TION).

So that is the "matter of taste" I speak of. If you're on the side that the RETURN call is implicit... just make FUNC translate the body of your function into a GROUP! and RETURN it, so that the ultimate body result is the return value:

func: adapt :lib.func [  ; runs the "prelude" block you give it before lib.func runs
    body: compose [return (as group! body)]  ; alters the BODY that lib.func sees
]

A little faster, but a little less readable (though I guess that's subjective):

func: adapt :lib.func [
    body: reduce ['return as group! body]
]

As with most things, this could be made native for more performance. We'd just have to give it a name.

func: :lib.returner-func

Something like that. I want to stress that I'm not opposed to having these optimized variations if something turns out to be really important to some people...it would run slightly faster than the adaptation.

You Can Has APPEND/ONLY

/ONLY is Dead...but Ren-C's flexibility means you can get it back if you want it, and not break a sweat doing so. You just become responsible for figuring out what its universal meaning is. (#goodluckwiththat)

Remember that AUGMENT lets you add parameters to functions.

>> foo: func [x] [print ["x is" mold x]]
>> parameters of :foo
== [x]

>> foo+: augment :foo [/only "An ONLY parameter"]
>> parameters of :foo+
== [x /only]

>> foo+ 10
x is 10

>> foo+/only 10
x is 10

But adding parameters doesn't actually do anything but expand the specification. You have to use another tool like ADAPT or ENCLOSE to make use of the new parameters that FOO never knew about.

>> foo++: adapt :foo+ [print either only ["/ONLY!"] ["no /ONLY"]]

>> foo++ 10
no /ONLY
x is 10

>> foo++/only 10
/ONLY!
x is 10

So here's an ONLIFY transformer that adds a refinement to a function, and then injects a little code to pre-process the parameter to make a block isotope if needed. (Note that the value passed to these functions is passed by ^META convention, so it will be quoted when a normal block is passed.)

onlify: lambda [
    {Add /ONLY behavior to APPEND, INSERT, CHANGE}
    action [action!]
][
    adapt (augment :action [/only "Use quoted semantics for value"]) [
        all [not only, any-array? series, any-array? unquote value] then [
            value: as block! unquote :value
        ]
        ; ...fall through to normal handling
    ]
]

Then you can apply it to the functions:

append: my onlify  ; e.g. `append: onlify :append` 
insert: my onlify
change: my onlify

And there you have it:

>> append [a b c] [d e]
== [a b c d e]

>> append/only [a b c] [d e]
== [a b c [d e]]
1 Like