How To Make Statics Aware of Function Arguments?

If you have parts of your function that are made on every call, you can improve performance by binding the body to statics.

e.g. instead of:

foo: func [
    some-arg
] [
   bar: func [...] [...]
   ...
   bar ...
]

You would move the definition of BAR out, so it only has to create the function once.

foo: func [
    some-arg
] bind {
   bar: func [...] [...]
} [
   ...
   bar ...
]

But it's often the case that these helpers want to see the locals of the function, on a per-instantiation basis. Something like this:

foo: func [
    some-arg
] bind {
   bar: func [y] [return some-arg + y]
} [
   ...
   bar ...
]

You can see @hiiamboris doing that by binding the object, to a function:

reshape.red

So basically he names the object, creates the function bound to the object, and then turns around and binds the object back to the function:

obj: {
   bar: func [y] [return some-arg + y]
}

foo: func [
    some-arg
] bind obj [
   ...
   bar ...
]

bind foo/ obj

Ren-C binding doesn't do this. And there are good reasons why.

But there might be something that can be done, with the leading dot variables. e.g. the functions could be methods?

foo: func [
    some-arg
] bind {
   [.]: ~  ; initialize to meaningless value
   bar: func [y] [return .some-arg + y]
} [
   [.]: binding of $return  ; or however you get the frame
   ...
   bar ...
]

Not that pretty, but at least it's possible. Problem is--though--that there's still only one static object bound to the function, so if the function recurses this breaks.

I think this is a scenario deserving of a solution. So worth thinking about.

I don't know if the following is crazy or not, yet...

:shaking_face:

But what if you make it a method, and then say that rather than it being an error to call a method as if it were a "free function", you use the meaning of dot that's currently in effect if a word has been explicitly bound to a methodized function?

Like this:

foo: func [
    some-arg
] bind {
   bar: func [y <.>] [return .some-arg + y]
} [
   let [.]: binding of $return  ; or however you get the frame
   ...
   bar ...
]

Note that this isn't the same as saying you don't need dot to dispatch methods in ordinary objects, because you don't get object words "scoped" into the "methods" of an object by default. You need the dot to get the visibility. But here, we bound the words into scope deliberately.

  • What stops you from doing this with methods is that you're defining the methods and the data at the same time, so you can't bind the bodies of the methods into the object a-priori because the object doesn't exist yet.

  • But here, the object can predate the function body. Hence you can only bring the object into scope after entry to the method--not before.

  • Slightly subtle difference in what's possible mechanically, but in effect you could make it the same with object methods...it just would cost a little more at runtime because you have to do the bind after the function is called. (You could abstract it so the source doesn't show the binding.)

I think this might be a pretty clean way to get this behavior, and it kind of makes sense...because what you are doing here is like saying "this function has methods".

:exploding_head: