What if FUNCTION with explicit <local> tag behaved as FUNC?

The current behavior of FUNCTION with a <local> tag is to let you specify explicit locals, while still gathering SET-WORD!s in the body. So a hypothetical example would be:

foo: function [a b <local> c d] [
    set [c d] reduce [a b]
    x: c + d
    return x
]

The example is kind of dumb, because the SET line could have used set [c: d:] ... in this case and gotten locals gathering behavior. In any case, the much more common case is to want to suppress locals gathering for a set-word (<with>, formerly known as /EXTERN) than to force locals gathering for non-SET-WORD!s.

FWIW, I've never used <local> with it's current behavior in a FUNCTION. There's also the ability to use SET-WORD! in the spec to specify locals without disabling locals gathering. Plus I don't feel like there's a whole lot of uses of FUNC...where FUNCTION vs. FUNC would make a difference...that don't have a /LOCAL in it.

So what if <local> meant don't do locals gathering, and FUNC went away. What we're really comparing here is:

 function [a b <local> c d]
 func [a b <local> c d]

At which point we're talking about a 4 character difference. And people who wanted to could abbreviate FUNC for FUNCTION and still get to say they wanted locals gathering or not in the same length while using FUNC for locals gathering also.

@rgchris has suggested that in cases of functions that are declared inside objects, the ergonomics of having something that doesn't do locals-gathering in order to get at the object fields is important. But I think there's a lot of work to be done there, with a METHOD that can somehow work with our new binding capabilities to avoid functions that have copies of their bodies made on every instance of an object class made. It may change the dynamics of that situation entirely.

In any case, I think it would be pleasing if "FUNC" were not necessary or in the box, so it's worth thinking about.

Not just objects but also using functions as callbacks where for the most part you want the function operating in the context of origin.

Looking again at ten steps, a function is defined this "... is a block which has local variables that are given new values each time the block is evaluated". Thinking along these lines func behaviour is the natural way to consider what a function is in Rebol. While auto-gathering helps avoid naive errors, it can lead to unexpected errors when working in more nuanced and complex situations (auto-gathering can only ever be clumsy). I suggest that auto-gathering should require a flag and func behaviour be the default for function.

And a pedantic counter-point, your suggestion is a 12 character difference for a basic func:

func [foo][...]
function [foo <local>][...]

I see your point. Though I'll also point out you haven't weighed in yet on what I would think would be a similar "clumsiness" of allowing random bindings to escape and lead to indefinite lifetimes of args/refinements/locals!

IF Rebol leans more to being an advanced, graspable, human-scale, natural-language-biased assembly language (with a wacky instruction set) than it is an abstract high-level language, it should be erring in these matters on the side of control and awareness. To keep people close to the "metal" of the reality of the interpreter core, and yet able to accomplish great feats despite that design.

A big thought, and as starting this thread indicates, I'm still encouraging the big thoughts. (I have not given up on = meaning strict equality, and is being lax equality, with isn't pairing with IS, apostrophe and all.)

So yes, well worth noticing we could bend it the other way...the parallel suggestion would be thus that function [foo <with>] [...] mean "with nothing", e.g. no assignments via-set-word reach out of the environment of the function.

It is true that classic FUNC is the more "basic" tool of Rebol and maybe a mistake to hide it, the other questions aside. I broke it down even further so that MAKE FUNCTION! is the most basic tool, which does not even define what the word RETURN means.

Lest people feel demoralized by the idea we're still talking about such "basic" questions, I'd like to remind people that today, we can do things like this:

 >> do-frame: function [f] [
      do f
      return "not returned from do-frame"
 ]

 >> something: function [y] [
     f: make frame! :return
     f/value: y
     do-frame f
     return "not returned from something"
 ]

 >> something 1020
 == 1020

I show that off--instead of just the usual "hey you can RETURN out of userspace loops"--because it was even harder to rig up inside the rules of the game. The pieces are composing, a FRAME! based on a definitional return can reconnect with the specific RETURN it was made for.

The mechanics of how this all can tie together, and the fact that FUNCTION can be built entirely in userspace (with a different term used for RETURN, or variations at your choice), is something that I feel is worth at least a little sense of awe.

So I don't want us to underestimate the value of continuing to push on the ground definitions. Maybe we not make any big moves until virtual binding advances a bit more, though. Making headway on that--in my opinion--would be something that changes quite a lot of how we look at the language.