World: r3wp
[!REBOL3 Proposals] For discussion of feature proposals
older newer | first last |
Ladislav 12-Nov-2010 [330] | (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 |
BrianH 12-Nov-2010 [376] | That is true, but not enough - the dynamic transparency proposal also has that quality. The main advantage that only definitonal return has is that it can do things that dynamic return can't, even with transparency. And it does so with almost no added overhead, because the functions were getting bound anyway. That is why I support it. |
Ladislav 12-Nov-2010 [377x2] | Yes, that looks to me as the main argument to support the definitional return as well. |
Nevertheless, as you mentioned above, the cost of binding may be prohibitive in cases when the block is supposed to be run only once (like in case of CATCH), which may indeed be the main reason, why to keep dynamic throw. | |
BrianH 12-Nov-2010 [379] | You don't lose anything that you haven't already lost for other reasons, and it is possible (in native code) to build in acceptable workarounds for its weaknesses, so there's no significant downside to definitional return (except the work Carl would have to do to implement it). |
older newer | first last |