r3wp [groups: 83 posts: 189283]
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

World: r3wp

[!REBOL3 Proposals] For discussion of feature proposals

Ladislav
12-Nov-2010
[326]
Blocks don't have to be nested

 - does it make any sense to you? It surely does not make any sense 
 to me.
BrianH
12-Nov-2010
[327x2]
Maybe you missed it, but there are better arguments against dynamic 
break. PARSE [(break)] is minor in comparison to the other problems.
Blocks don't have to be nested
  a: [] b: [a]
Not nested, dynamic scope.
Ladislav
12-Nov-2010
[329x2]
I do understand that "blocks don't have to be nested", but that does 
not relate to the fact, that break in parse behaves lexically
(and make no mistake, I mean the parse keyword, not the foreign (break) 
construct)
BrianH
12-Nov-2010
[331]
The BREAK keyword does not break out of the nearest loop lexically, 
it breaks out of the nearest in the (PARSE equivalent of the) call 
chain. It is dynamic in scope, which can easily be demonstrated with 
ANY, SOME or WHILE with a named rule with a BREAK in it, instead 
of an inline block.
Ladislav
12-Nov-2010
[332]
{very novice question - parse [break] is not the same as parse [(break)] 
internally?} - correct, they are two completely unrelated constructs, 
the latter being "foreing" to parse, related to the do dialect, in 
fact
BrianH
12-Nov-2010
[333]
If you call a rule through a name, you are using dynamic scope. If 
the rule is inline then it is lexical scope.
Ladislav
12-Nov-2010
[334x2]
Are you suggesting, that you cannot name things in lexically scoped 
constructs?
I simply don't understand, how it relates to the subject
BrianH
12-Nov-2010
[336]
You can not refer to structures by name in lexically scoped constructs, 
when those names are resolved at runtime. Well, you can, but then 
that becomes a dynamically scoped flow construct.
For instance:
a: [break]
b: [while a]


The word 'a is in the lexical scope of b, but the contents of a are 
in its dynamic scope only if b is used as a parse rule at runtime 
and a is still assigned that value. So even though the break is a 
keyword, the scope to which it breaks is the while, which is in b.
Ladislav
12-Nov-2010
[337]
... I know that Ladislav's DO-ALL is a loop, and so not wanting BREAK 
to apply to it is more of an opinion than something inherent in its 
nature.

 - I was afraid, that the DO-ALL was not a fortunate choice! My original 
 problem with the property illustrated by DO-ALL occurred when I Implemented 
 my PIF (now called CASE for the newcomers), which was not meant to 
 catch any breaks, as is immediately obvious.
BrianH
12-Nov-2010
[338x2]
Yup. Hence the "we need this" comment (paraphrased).
It was just a caveat, not a criticism.
Ladislav
12-Nov-2010
[340]
I wanted to invent as a simple example as possible, but I oversimplified, 
obtaining something, that may not be easily justifiable
BrianH
12-Nov-2010
[341x3]
It's cool. Your point was made, and the disadvantages of definitional 
break that you hadn't gotten around to adding to the page yet are 
stated above in that big message.
Btw, have you seen the source that would be used to implement definitional 
return? It would help to know whether they were catchable for debug/test 
purposes.
Debug/test needs a standard way to catch everything, but afaict there 
is no way to do so with definitional return. The same would go for 
the others if they were definitional, but that is less likely for 
the reasons given above. We might just have to live with not being 
able to catch definitional return - it should be easy to control 
the test environment so its return functions don't propagate into 
the test code, so that probably won't be a problem, at least for 
returns.
Ladislav
12-Nov-2010
[344x2]
Loops are also defined lexically,

 - yes, as far as loops with variables are considered, the loop variables 
 are definitional, not dynamic
For variable-less loops the situation is different: not using "private 
variables" they are neither definitional nor dynamic
BrianH
12-Nov-2010
[346x3]
Yup. But I was mostly referring to the standard way the loop functions 
are used. Most loops are mostly made up of nested blocks and such, 
with very little direct DO calls to other blocks by name.
DO (or IF, or ALL, ...) of a block by name tends to only show up 
in advanced code. That code tends to be critical, and we usually 
can't afford to make it non-working, but not many people do that 
level of hand-optimization of their code, mostly because their code 
isn't that speed or size critical, or they don't know how (or they 
don't like that technique). On the other hand, PARSE rules called 
from loops are often referred to by name and are moved physically 
outside of the loops that call them for really good reasons, some 
of which I mentioned above.
Carl uses the manual CSE trick a lot - I learned to do so from him 
:)
Ladislav
12-Nov-2010
[349]
{Ladislav, your definitional throw in the "Definitional CATCH/THROW 
mezzanine pair" section of your page isn't recursion-safe, because 
MAKE function! does a modifying BIND rahter than a non-modifying 
BIND/copy. } - I know that, but, since it is just an example, and,since 
it can be asily updated to copy, I wrote it this way. I can add copying, 
though
BrianH
12-Nov-2010
[350]
Cool. It's a good hack, and it does a good job of illustrating the 
overhead of the definitional throw approach.
Ladislav
12-Nov-2010
[351]
The only difference would be to replace the (block) by (copy/deep 
block)
BrianH
12-Nov-2010
[352]
Right. COPY/deep is expensive for large code blocks, worse than BIND/copy 
(depending on the code). Copy overhead is a big deal.
Ladislav
12-Nov-2010
[353]
If it is more expensive, then there is a question, whether we should 
not have a less expensive variant...
BrianH
12-Nov-2010
[354]
Especially for CATCH. The more useful CATCH is (measured in levels 
skipped) the more code you need to copy.
Ladislav
12-Nov-2010
[355]
(my note was realted to the bind/copy refinement)
BrianH
12-Nov-2010
[356]
The BIND/copy overhead is inherent in definitional scoping, except 
for function and closure creation where it is only a BIND, which 
was happening anyway. That is why definitional return is cost effective
Ladislav
12-Nov-2010
[357x10]
Bind/copy may be inherent, but my not was a reaction to: "COPY/deep 
is expensive for large code blocks, worse than BIND/copy" - which 
may not be desired
Regarding the above suggested example:

a: [break]
b: [while a]


That is really interesting, because if you really test it, you shall 
find out, that it does not break out from WHILE
(it breaks out from A, and there is nothing WHILE can do except A)
c: [3 a]
is similar
you can make sure as follows:
d: [while [a]]
...which proves, that break breaks out from A actually, i.e. from 
the lexically closest construct
Update to the

http://www.rebol.net/wiki/Exception_proposals

article. Changes:


- description of Dynamic versus Definitional return with example 
(the one from the Carl's article is used)

- I am still not sure, whether I should put in the description of 
dynamic versus definitional variables, so, Max, if you think you 
know how would you like it to look, go ahead an put it in
Also, I adjusted the implementation of the definitional Catch/Throw 
pair in R2-like variant to:


- use FUNC instead of MAKE FUNCTION! to have the body (deep) copied
- unset 'throw for localization purposes
BrianH
12-Nov-2010
[367x2]
Yeah, that break thing, I forgot: An interesting thing about PARSE 
was revealed during the course of implementing the parse proposals. 
It turns out that what most people (including me) thought about PARSE 
was wrong. ANY, SOME and WHILE aren't the only loops in PARSE for 
BREAK to break out of: Every rule is a loop. Even rules that don't 
have any iteration or repetition are effectively a LOOP 1. This means 
that while the *scope* of the BREAK operation in PARSE is definitely 
dynamic in its implementation (this also came out in discussions 
with Carl, though it doesn't use the unwind method), it is (afaik) 
impossible to construct a working example of BREAK that demonstrates 
this. I would love it if you could figure out how to write example 
code to prove this, Ladislav, since I've just been taking the author's 
word for it.
It doesn't matter for R2 and R3's implementations of PARSE, but it 
might matter for someone who wants to make a compiler for the PARSE 
dialect (which is at least theoretically possible). That would be 
a really cool project :)
Ladislav
12-Nov-2010
[369]
I guess, that it may be implemented dynamically, but, the way it 
is implemented, makes it indiscernible from lexical. And, finally, 
what matters most is not the implementation, but the behaviour.
BrianH
12-Nov-2010
[370]
Dynamic scope and lexical scope have a lot of overlap. Being different 
in kind doesn't necessarily make them different in practice :)
Ladislav
12-Nov-2010
[371]
So, if the BREAK in Parse actually always breaks out from the lexically 
closest block containing it, the behaviour is lexical, at least that 
is what I think the definition is about.
BrianH
12-Nov-2010
[372]
Of course, that is what makes it possible to consider changing to 
definitional return. If it was too different in practice, it wouldn't 
be an option, too much code would break and too much of the understanding 
of developers would break too.
Ladislav
12-Nov-2010
[373]
...and, the biggest disadvantage of the dynamic return is the opposite 
- the fact, that knowing the lexically closest catching construct 
does not tell you, which construct will be the closest one at run 
time
BrianH
12-Nov-2010
[374]
PARSE operates on dynamic scope, but many of its constructs are affected 
by the closest thing that REBOL has to real lexical scope: nested 
structures. Basically, the only real lexical scope in REBOL is the 
kind you can get from an unbound LOAD. The rest is faked using "definitional" 
processes. And the definitional process is itself dynamic (though 
it is a one-way process, so its scope isn't bounded).
Ladislav
12-Nov-2010
[375]
Right, the main advantage of the definitional approach is, that it 
resembles the lexical case very well, where needed, and only in exceptional 
cases it looks differently