REBOL3 tracker
  0.9.12 beta
Ticket #0002173 User: anonymous

Project:

Previous Next
rss
TypeBug Statusdismissed Date28-Sep-2014 18:03
Versionr3 master CategoryEvaluation Submitted byfork
PlatformAll Severitynot a bug Prioritynormal

Summary Lookahead for infix triggers error before evaluating terms
Description If you write the following:

foo: function [a b] [
c: 10
d: 20
return [print "Hello" c print "Cruel" d print "World"]
]
reduce foo 1 2

You'll not get any print output, and you instead get:

*** Error: undefined context for word 'c

Users might be confused by this (I was) because it seems a completely fulfilled PRINT expression should be executed before discovering the error on `c`.

What has happened is indeed that `print` has been resolved as a function with one argument, and it is attempting to fulfill that argument. But as part of that fulfillment, `"Hello" c` is being checked to see if c is an infix operator before it can decide if it's okay to pass the "Hello" to print as-is. The infix check fails because it can't look up c even to see if it is unset. (If it were merely unset, this would not happen.)

Consider this other code which doesn't raise an error, but presents a bit of a thinking point:

foo: func [bar] [
print bar
c: :+
1000
]
foo 10 + 20 c 30

If `c` were infix at the outset of this expression, then it would have been called on 20 and 30. Since it isn't, we call `foo` with 30 (10 + 20). During the course of running foo, `c` becomes infix. We either accept that and give back 1030, or raise an error.

Not entirely sure what the answer should be, but as it is makes me uncomfortable. It seems that once an infix test has been done in order to determine the order of an operation, it shouldn't be able to change. If you let it do so, then the precedence itself is shifting in *mid-evaluation*.

Red has this issue currently, as well as another one:

https://github.com/red/red/issues/941

So a decision is needed there too.
Example code

			

Assigned ton/a Fixed in- Last Update21-Oct-2014 17:34


Comments
(0004524)
BrianH
21-Oct-2014 17:34

It's not the lookahead for infix that's causing the problem, it's that at the time you are evaluating the REDUCE of the block, the context to which the 'c is bound is not valid. The context of a function is stack-relative, and the values of words bound to the function context are looked up in the stack. As such, the stack frame in question only exists when the function is running. Words bound to such a context are only valid to dereference when their context is valid.

To do what you want here, you need to use a closure, like this:
foo: closure [a b] [
c: 10
d: 20
return [print "Hello" c print "Cruel" d print "World"]
]
reduce foo 1 2

The context of a closure is created for each run of the function, and as such is able to persist after the function finishes running.

In your second example, you use the non-locals-gathering FUNC. Let me guess: You ran this in a script or from the console, which is why the word 'c in your following statement was defined at the top level; since it was not overridden by a local 'c in the function, you were assigning a value to the outer 'c, which was then able to be evaluated since its context still existed. The infix thing was a red herring, the real difference was between FUNCTION and FUNC.

There's a lot more detail about the difference between function and closure contexts in #1893, where the security implications of all this were analyzed. But for the code you're talking about here, it's not a bug.

Date User Field Action Change
21-Oct-2014 18:14 BrianH Comment : 0004524 Modified -
21-Oct-2014 17:34 BrianH Severity Modified major => not a bug
21-Oct-2014 17:34 BrianH Status Modified submitted => dismissed
21-Oct-2014 17:34 BrianH Comment : 0004524 Added -
28-Sep-2014 21:41 Fork Description Modified -
28-Sep-2014 21:40 Fork Description Modified -
28-Sep-2014 21:40 Fork Category Modified Unspecified => Evaluation
28-Sep-2014 21:36 Fork Severity Modified minor => major
28-Sep-2014 18:23 Fork Description Modified -
28-Sep-2014 18:03 Fork Ticket Added -