World: r3wp
[!REBOL3]
older newer | first last |
Sunanda 3-Mar-2010 [1132] | Or: loop 2 [print true attempt [continue] print true] |
Henrik 3-Mar-2010 [1133x2] | Once, and it did. |
Twice, and it did. | |
BrianH 3-Mar-2010 [1135] | The question (only for Carl) is whether task-local runtime contextual information can be made available to BREAK, EXIT, RETURN and THROW to let them know that they are going to be handled by the console, which would let them throw the error that the console should be throwing, on behalf of the console. Basically, letting them be more polite. The problem is that it is *really* likely (only Carl would know) that this would slow down all function! and closure! calls, all loops, and every call to DO (even indirectly, as in IF) by quite a bit. It could make R3 a lot slower (maybe several times slower). |
Henrik 3-Mar-2010 [1136] | I'm not sure what you would expect here. Wrapping break and continue in attempt has no effect, because we know there are no errors inside the attempt block and the context outside is correct for break and continue. The attempt has absolutely no effect here. |
BrianH 3-Mar-2010 [1137] | Right. |
Henrik 3-Mar-2010 [1138] | I'm curious now: How do those functions know they are inside loops and functions? |
Pekr 3-Mar-2010 [1139] | They ask Carl :-) |
BrianH 3-Mar-2010 [1140x2] | They don't, not in the slightest. |
They are thrown like exceptions. The default handler is in the console. | |
Henrik 3-Mar-2010 [1142] | I see. That further proves how little ATTEMPT has to do with these errors. :-) |
BrianH 3-Mar-2010 [1143x4] | And in REBOL there is no way to statically determine whether an exception will be handled without tracing the code. You could in theory determine it at runtime (from the internals), but that would have overhead. The question is how much overhead. |
ATTEMPT and TRY push a handler for exceptions with codes over 100 on the task-local handler stack. Those exceptions are generated by DO MAKE error! (or code called by natives with the same effect). | |
The interesting part of the default console handler is that it is exactly the same handler that displays regular errors. The messages come from here: >> system/catalog/errors/throw == make object! [ code: 0 type: "throw error" break: "no loop to break" return: "return or exit not in function" throw: ["no catch for throw:" :arg1] continue: "no loop to continue" halt: ["halted by user or script"] quit: ["user script quit"] ] | |
Sorry for the awkward phrasing above. The comments in the ticket read better. | |
Paul 3-Mar-2010 [1147] | Brian, I agree with you. I think if we make Try or Attempt handle these other exceptions then we are going to slow things down. Again, we have a way to handle this now. No need to pursue the problem at this point. |
Andreas 3-Mar-2010 [1148x3] | This `attempt [break]` debate is really interesting. |
I think it uncovered not a bug in the implementation, but provokes a discussion on the language semantics. | |
I guess I'll have to write that up in more detail :) | |
Sunanda 3-Mar-2010 [1151] | Thanks for the repeated attempts to explain, Brian! For me, the work around is: error? try [....] That seems to work in all cases I have tried. [Ironically, 99% of all the REBOL code I have ever written uses ERROR? TRY -- ATTEMPT did not exist when I started REBOL, and my fingers have learned to type the idiom. It's only with R3 that I'ved tried to update my error handling.....Seems I should stick with my older ways for a while...:)] |
Andreas 3-Mar-2010 [1152x4] | Ok, I've written up some of my thoughts at http://www.rebol.net/wiki/User_talk:Andreas#Notes_on_Bug.231506_--_on_control_transfer_functions |
The gist of it: I think most control transfer functions should be unbound globally, and only bound in code executing within their respective control transfer handler. | |
For example, BREAK should be unbound globally, and bound only within loop bodies. | |
That means, an erroneous use of e.g. BREAK would simply result in a "has no value" error, just as the use of any other unset word. And this error would of course be nicely caught by ATTEMPT. | |
Sunanda 3-Mar-2010 [1156] | The crux of the issue for me is this: attempt [badcode] print true I (naively perhaps) suggest that this should always either: -- close the console (if badcode has a QUIT); or -- halt (if badcode has a HALT; or -- print TRUE in all other cases. Brian argues that there are internal engineering reasons for a fourth possibility: -- ATTEMPT returns an error message |
Andreas 3-Mar-2010 [1157x4] | I think that your suggestion is not naive but very reasonable |
And I also think there's an easy way to fix things that they work as you expect | |
Easy from a language design perspective, that is. | |
I also think it is reasonably straightforward to implement and has no significant impact on performance. But I don't have the time to write down why I think this, at the moment. | |
BrianH 3-Mar-2010 [1161x2] | Sunanda, that error? try [....] code you keep mentioning doesn't work in all cases you mention. The problem is this: >> error? break == true This is an error (bug#771 and bug#862): It should not return true, it should break and then later on trigger an error for an unhandled break. To illustrate why: >> loop 1 [error? break 'buggy] == buggy That should have returned unset, not continued. The BREAK is supposed to halt execution and resume it somewhere else, either after the enclosing loop or at the top level. The same error is affecting your error? try [....] code, which is not behaving correctly. Your problem, Sunanda, is that you are thinking that ATTEMPT is not catching bad code (bugs) that it is supposed to catch - this is not strictly true. ATTEMPT isn't supposed to catch bugs, it is supposed to catch triggered errors. And a lot of logic bugs don't trigger errors, because the code itself is technically correct (what REBOL can check for), but not in accordance with the programmer's intentions (which REBOL can't know). Now in this case the logic bug is that you have forgotten that the purpose of the BREAK, CONTINUE, THROW, EXIT and RETURN functions is escape from the normal flow of the code ("structured" gotos, aka non-local returns, exceptions, ...) - you remembered this about HALT and QUIT - and didn't realize that the error you are trying to catch with ATTEMPT is not in the code that you have wrapped in the ATTEMPT: It is not bad code. The error is triggered by the code on the other end, the handler, which is not wrapped in the ATTEMPT at all. So you need to realize that this code is technically correct: >> attempt [break] ** Throw error: no loop to break but doesn't do what you thought it should. And this code is absolutely incorrect: >> error? try [break] == true but doesn't trigger an error because of a weird design quirk in R3 that is arguably a bug, but not necessarily fixable (see bug#771 and bug#862). |
Created a ticket (bug#1509) to explain the real problem with these functions. | |
Paul 3-Mar-2010 [1163x3] | do we really want this behavior: >> obj: construct [a: b: c: 1] == make object! [ a: 1 b: 1 c: 1 ] |
I think we need a way to pass that block so that 'a and 'b can evaluate to none | |
It is clear why it setting a and b to 1 but we need to have something a bit safer. | |
BrianH 3-Mar-2010 [1166x2] | We want that behavior and much code depends on it. You can add the none explicitly if you need that value. |
And CONSTRUCT doesn't evaluate anything, so safety is not an issue. | |
Paul 3-Mar-2010 [1168x2] | Still we need to check it and we could simply have another switch that could fix construct to be even more superior. |
construct/as-is | |
BrianH 3-Mar-2010 [1170] | We have that option, except it's called /only. |
Paul 3-Mar-2010 [1171x2] | that doesn't work for this issue |
>> a: construct/only [c: d: 1] == make object! [ c: 1 d: 1 ] | |
BrianH 3-Mar-2010 [1173] | Chained assignments aren't an issue, they are an intended feature. |
Paul 3-Mar-2010 [1174] | I understand that but we need a feature in which they are NOT. |
BrianH 3-Mar-2010 [1175] | >> construct/only [a: b:] == make object! [ a: none b: none ] |
Paul 3-Mar-2010 [1176] | that is still a chained assignment |
BrianH 3-Mar-2010 [1177] | But that's not a problem. |
Paul 3-Mar-2010 [1178x4] | Ok, it doesn't seem your following me, so let's forget about construct. |
We need a function that does not evaluate or do chain assignment. | |
But let's you access the elements as if they are an object and can already exist in a block style spec that can be passed to context. | |
So it would be similiar to construct except without the chain assignment. | |
older newer | first last |