REBOL3 tracker
  0.9.12 beta
Ticket #0002221 User: anonymous

Project:

Previous Next
rss
TypeIssue Statusproblem Date13-Jul-2015 14:30
Versionr3 master CategoryNative Submitted byrgchris
PlatformAll Severitymajor Prioritynormal

Summary BODY-OF strips a function body of any context.
Description Using BODY-OF to obtain the body of a function (deep) strips the context from the content of the resultant block. This precludes use of the body in any meaningful way, for example building a derivative function.
Example code
>> do foo: does [print "Foo"]
Foo
>> do foo: does body-of :foo
** Script error: print word is not bound to a context
** Where: function!
** Near: :foo

Assigned ton/a Fixed in- Last Update5-Jan-2016 04:20


Comments
(0004649)
fork
24-Jul-2015 09:48

The reflector for functions was doing an Unbind_Block on the copy of the body before returning it. As you say, this makes the body fairly useless.

On a mechanical level, there is an argument against allowing words bound to function locals to "escape". In FUNCTION!s, the words are bound "stack relative"...which is to say that once you get them out of the function they're in, you can't get a value. (Unless that function is above you on the stack, in which case you'll get the value of the nearest invocation above you on the stack.) The argument against allowing them to escape for a CLOSURE! could be considered stronger, as the bound locals are actually just placeholders which can *never* be looked up (the body is copied and words rebound to a real frame).

But philosophically in metaprogramming, it seems you could well be interested in a distinction between unbound words in a function body, and those which were bound to function parameters. So it's worth thinking about how to get past the mechanical issues to offer that detection. But so long as BIND? (`binding-of`) can only return TRUE for any word bound to a function! local, you would be unable to tell the difference between a word bound to an inner function's locals or an outer function containing it.

foo: func [x] [
bar: func [y] [
x y
]
body: body-of bar
if (bind? body/1) == (bind? body/2) [
print {Yup, they're both... locals to something. But what?}
]
]

Being able to ask something like **bind? body/1** above and get back the function value for foo is not something that's mechanically set up right now, but it could be done. Harder would be if these were closures, because with a closure the binding has to be to the instance of the context for that closure call. So this means you might be interested in binding to that closure instance OR getting to the archetypal closure to ask about its body. :-/ So there'd have to be a new type representing a closure instance... CLOSED! ? Anyway, something that you could bind to representing an instance as well as get access to its body.

Barring knowledge of what the right thing to do here is right this minute, Ren/C is taking the "don't introduce any new kinds of problems" approach. Today, closures cannot leak local references out of their body (with negative in-frame indices) because you never invoke a closure without its body being scanned and glued to an object created for that call. But a function can leak them just as easy as:

foo: func [x] [return [x]]

So what I've done is to unbind the closure's local references, and leave the ones in the function alone. It's a short-term answer but hopefully one that decreases pain for now. Result is like:

>> foo: function [x] [print x]
>> bind? second body-of :foo
== true

>> bar: closure [x] [print x]
>> bind? second body-of :bar
== none

https://github.com/metaeducation/ren-c/commit/5267b001dc6dec345a5d04fda43e1cce8dc0bb7a
(0004677)
Ladislav
5-Jan-2016 04:17

Carl implemented this change and a couple of other limitations as a safety measure to restrict access to internals of "private" functions.
(0004678)
Ladislav
5-Jan-2016 04:20

"On a mechanical level, there is an argument against allowing words bound to function locals to "escape"." - this is actually unrelated, the discussed measure "protects" other words in the function body as well.

"...so long as BIND? (`binding-of`) can only return TRUE for any word bound to a function! local, you would be unable to tell the difference between a word bound to an inner function's locals or an outer function containing it." - that is actually false, such a detection *is* possible.

Date User Field Action Change
5-Jan-2016 04:34 ladislav Comment : 0004678 Modified -
5-Jan-2016 04:20 ladislav Comment : 0004678 Added -
5-Jan-2016 04:17 ladislav Code Modified -
5-Jan-2016 04:17 ladislav Status Modified submitted => problem
5-Jan-2016 04:17 ladislav Comment : 0004677 Added -
24-Jul-2015 09:48 Fork Comment : 0004649 Added -
13-Jul-2015 14:30 rgchris Ticket Added -