World: r3wp
[!REBOL3 Proposals] For discussion of feature proposals
older newer | first last |
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). |
Ladislav 12-Nov-2010 [380] | In the case of BREAK (I mean the one used in the DO dialect now), the situation is 50:50, since loops would be bound once, done many times anyway, making any slow-down % much smaller, and due to the fact, that some loops (as you mentioned earlier too), need to bind their bodies anyway |
BrianH 12-Nov-2010 [381] | The main reason to keep dynamic throw is that you would (practically) lose a lot of capabilities if you lost it; the reason you already lost those capabilities for functions don't apply to throws, so it would be a real loss. |
Ladislav 12-Nov-2010 [382] | (and, that applies to the CONTINUE case as well) |
BrianH 12-Nov-2010 [383] | I don't know how much R3 code you've had to optimize, but I've had to optimize it a lot. That BIND/copy overhead is significant. It takes a *lot* of loop reps to balance it out, more than most code needs to do by something like an order of magnitude. It's not 50:50. |
Ladislav 12-Nov-2010 [384] | Well, but don't forget about the binding being done anyway, which makes the binding time actually negligible |
BrianH 12-Nov-2010 [385x3] | Carl has mused that there might be a faster way to do BIND/copy in loops. It would be welcomed. |
The binding time is *not* done anyway by all loops. It is only done by REPEAT and *EACH, and we now often avoid using those functions *because* they rebind. REPEAT and *EACH are mostly used for small loop code, because of that binding time *and memory use*, which is even more significant than time in a lot of cases. | |
Code optimized to R3's characteristics is *much* more efficient in R3 than code optimized for R2. And it look better too (that was one of the reasons for a lot of the native changes). | |
Ladislav 12-Nov-2010 [388] | Well, I do not hesitate to use Foreach or Repeat where appropriate |
BrianH 12-Nov-2010 [389] | Nor do I. |
older newer | first last |