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

World: r3wp

[!REBOL3]

Paul
2-Mar-2010
[1097x2]
This way your only evaluating the DEFUSE code when needed so that 
ATTEMPT is free to be used in loops in controlled code.
Also, thanks for the explanation Brian, I see you answered my question 
regarding Construct.
Gregg
2-Mar-2010
[1099]
Great analysis Brian. And I think Sunanda's point about arbitrary 
code is the key element for me. Some things we can address with language 
"Don do that", but error handling like this is very important to 
get right, and explain clearly (with examples of how to write robust 
apps).
Sunanda
2-Mar-2010
[1100]
I've given it some more thought and think I have combined two issues 
that could better be dealt with separately:

1. TRY and ATTEMPT as ways of protecting my code:

Generally, the current behavior is surprising but in most cases acceptable.

It is rare that something as stupid as attempt [exit] would make 
it to production status. So, in many cases  no problem. [perhaps 
an odd problem if my app is generating code (eg a genetic algorithm). 
But knowing the problem, that could be guarded against]. 

2. TRY and ATTEMPT for protecting arbitrary code

As Gregg suggests, that needs a careful, systems-level design to 
get right and to make robust. REBOL3 offers some help (SECURITY policies, 
ATTEMPT, TRY, CALL) but isolating code into a safe sandbox, and recovering 
from any possible error/lapse/attack is not something the language 
alone can provide.


Still, making TRY and ATTEMPT fully predictable [succeed or return 
an ERROR] would be most welcome!
BrianH
3-Mar-2010
[1101x2]
The trick, Sunanda, is that the code that you want ATTEMPT to catch 
isn't actually erroneous. EXIT itself never generates an error - 
it basically is like a fancy goto that has to be caught by a handler. 
However, the handler can trigger an error (the one that you see) 
if the goto supposedly isn't handled; actually, all such goto functions 
are always handled and never cause an error directly, it is the handlers 
that cause the error.


The problem is really one of perception: Code that you think is erroneous 
(but isn't) is not triggering errors (and shouldn't), and the code 
that is triggering the error is not actually inside the code block 
that you are passing to TRY or ATTEMPT. Perceptual problems are tricky 
- either you have to change your perceptions, or rewrite the basic 
semantics of the language. Which is easier in this case?
ATTEMPT [exit] is never an error on its own. The error strictly comes 
from the context surrounding that code, not the code itself.
Sunanda
3-Mar-2010
[1103]
But 
  exit
_is_ an error on its own.

It is hard to see why ATTEMPTing an error "is never an error on its 
own", especially as trying it by itself in a console does create 
an error.  
  exit  ;; REBOL says is an error
  attempt [exit]  ;; Brian and I disagree if this is an error

it creates a horribly inconsistent mental model.

You could create a trivia/gotcha quiz arond this. Which of these 
stop with an error?
  attempt [throw]
  attempt [throw 0]
  attempt [throw/break]
  attempt [throw/break 0]
  attempt [throw/name]
  attempt [throw/name 0 0]
  attempt [throw/name 0 'x]
BrianH
3-Mar-2010
[1104x3]
But it's not EXIT that is generating the error. EXIT itself is innocent.
Sunanda, you are ignoring context. None of those generate an error. 
It is the code surrounding that code that generates the error.
Wait, the THROW/break ones always generate an error. THROW doesn't 
have a /break refinement.
Sunanda
3-Mar-2010
[1107]
But the only code surrounding it is the console!
BrianH
3-Mar-2010
[1108x2]
Yup, that is what is generating the error, the console.
And the first two THROW/name examples are wrong too, because of argument 
compatibility.
Sunanda
3-Mar-2010
[1110]
Then the console is broken!
BrianH
3-Mar-2010
[1111x2]
No, it's doing its job. It is only context that makes that code erroneous 
(except for 5 argument errors in your examples).
THROW 0 is always correct in and of itself. It's not THROW's fault 
you called it outside of a CATCH, it's yours.
Pekr
3-Mar-2010
[1113x2]
So how to catch concole errors then?
Simply put - we have to have chance to catch ANY level erorrs - your 
app can't crash on you, without your control imo ...
BrianH
3-Mar-2010
[1115]
The problem is that the code he is complaining about isn't actually 
erroneous.
Sunanda
3-Mar-2010
[1116]
How then can I get this code, executed from the command line, to 
always quit?
  r3-a97-3-1.exe --do "print true attempt [exit] print true quit"
Henrik
3-Mar-2010
[1117]
does it not print an error message?
BrianH
3-Mar-2010
[1118]
It's the missing CATCH that is the error, not the THROW.
Henrik
3-Mar-2010
[1119]
I guess ATTEMPT is no longer an extension of error? try like in R2.
BrianH
3-Mar-2010
[1120x2]
No, but it works the same, just faster. Almost all functions that 
had a [throw] attribute in R2 (or needed one, like ATTEMPT) were 
converted to natives in R3. We're still waiting for the new equivalent 
of the [throw] attribute to be added to R3 - right now USE, OBJECT 
and CONTEXT are the only built-in functions that still need it, afaik.
Note that the ticket was marked as a problem, not dismissed (yet). 
The problem was explained in the comments, and more thoroughly now 
in my more recent reply there.
Sunanda
3-Mar-2010
[1122]
I think I can answer my own question about executing arbitary code.

Just tried the ancient error? try technique:

   error? try [break]  ;; I'm happy
   attempt [break]   ;;  still think this is a bug!
BrianH
3-Mar-2010
[1123x3]
Actually, the first is an error too. It turns out that the way BREAK, 
EXIT, RETURN, THROW, HALT and QUIT work is by throwing pseudo-errors 
that are technically instances of the error! type, but not really 
errors. The ERROR? function disables that throwing for all error! 
values, even the fake ones. It's an error in ERROR?.
There's even a CureCode ticket for it, which you referred to in your 
comment.
It's the same error as RETURN BREAK.
Henrik
3-Mar-2010
[1126]
From my perspective, attempt [break] is working correctly. ATTEMPT 
has nothing to do with the BREAK, it simply passes it to the outer 
context (if you can say that) and then the BREAK doesn't hold up, 
because it's not inside a function. Seems simple to me.
BrianH
3-Mar-2010
[1127]
Loops, but yeah.
Henrik
3-Mar-2010
[1128x3]
yes, sorry, loops, not functions.
loop 2 [attempt [break]] works as expected.
>> a: does [attempt [exit] 1]
>> a
>>

Looks fine and dandy.
Sunanda
3-Mar-2010
[1131x2]
What would you expect from:
  loop 2 [print true attempt [break] print true]
true printed 0..6 times?
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.