Help me, Obi Reb Kenobi, you're my only hope!
[1/34] from: edanaii::cox::net at: 27-Aug-2002 19:51
OK, so what's going on here.
I'm trying to put a little error handling around my application. If it
fails, I need it to send out an alarm. But, depending on the statement,
I get an error when trying to trap the error.
For example, this works as expected:
>> If Error? Fred: Try [ 1 / 0 ] [ Print "Whatever!" ]
Whatever!
As does this:
>> If Error? Fred: Try [ 1 / 1 ] [ Print "Whatever!" ]
== none
This too:
>> If Error? Fred: Try [ Print ] [ Print "Whatever!" ]
Whatever!
But this doesn't:
>> If Error? Fred: Try [ Print "Get a grip!" ] [ Print "Whatever!" ]
Get a grip!
** Script Error: Fred needs a value
** Near: If Error? Fred: Try [Print "Get a grip!"]
This is confusing because why should I get an error on something that
doesn't and shouldn't cause an error.
This works, of course:
>> If Error? Fred: Try [ x: 1 ] [ Print "Whatever!" ]
== none
And this:
>> If Error? Fred: Try [ x: 1 / 0 ] [ Print "Whatever!" ]
Whatever!
And so do these:
>> If Error? Fred: Try [ Do [ 1 / 0 ] ] [ Print "Whatever!" ]
Whatever!
>> If Error? Fred: Try [ Do [ 1 / 1 ] ] [ Print "Whatever!" ]
== none
What's perplexing about the previous two is that it is a "Do" statement
that I am trying to execute and trap. Instead of functioning as above,
it blows up and gives me the "needs a value error".
And curiously, not only does Print fail, but so does Write. And that is
a function that I need error trapping on, if ever there was one.
>> If Error? Fred: Try [ Write %Temp.txt "Yup!" ] [ Print "Whatever!" ]
** Script Error: Fred needs a value
** Near: If Error? Fred: Try [Write %Temp.txt "Yup!"]
I've even tried disarming the error, but to no avail:
>> If Error? Fred: Try [ Write %Temp.txt "Yup!" ] [ Print "Whatever!" ] Disarm Fred
** Script Error: Fred needs a value
** Near: If Error? Fred: Try [Write %Temp.txt "Yup!"]
So what gives? Is this some subtle intricacy of the language, a bug, or my normal state
of confusion?
--
Sincerely, | Mud can make you prisoner, and the plains can bake
Ed Dana | you dry. Snow can burn your eyes, but only people
Software Developer | make you cry.
1Ghz Athlon Amiga | -- Lee Marvin, Paint Your Wagon.
=========== http://OurWorld.CompuServe.com/Homepages/EDanaII ===========
[2/34] from: al:bri:xtra at: 28-Aug-2002 17:11
> And curiously, not only does Print fail, but so does Write. And that is
a function that I need error trapping on, if ever there was one.
>> type? try [print "The Force will be with you; always."]
The Force will be with you; always.
== unset!
>> type? try [write %Force.txt "The Force will be with you; always."]
== unset!
Both 'print and 'write return a unset! value, which can't be "assigned" as a
value to 'Fred, by the set-word "Fred:". Perhaps 'attempt from the latest
Rebol/Core might be more useful to you:
>> source attempt
attempt: func [
{Tries to evaluate and returns result or NONE on error.}
value
][
if not error? set/any 'value try :value [get/any 'value]
]
I hope that helps!
Andrew Martin
Rebol Superhero! :)
ICQ: 26227169 http://valley.150m.com/
[3/34] from: carl:cybercraft at: 28-Aug-2002 17:49
Hee - wasted time on this myself today!
The problem is that 'print doesn't return a value when 'Fred is
expecting one...
>> Fred: print "What's wrong with this?"
What's wrong with this?
** Script Error: Fred needs a value
** Near: Fred: print "What's wrong with this?"
and it's not trapped by your error routine as 'Fred is outside the
block that's being 'try'ed. Place 'Fred inside it and you'll trap
the error...
>> If Error? try [Fred: Print "See?"][Print "Whatever!"]
See?
Whatever!
It's possible to write a function that'll check for nothing returned,
as the any-type! datatype will accept nothing. ie...
nothing-check: func [value [any-type!]][
either value? 'value [join "that was: " value]['nothing...]
]
>> nothing-check "abc"
== "that was: abc"
>> nothing-check print "abc"
abc
== nothing...
>> nothing-check join "abc" "xyz"
== "that was: abcxyz"
>> nothing-check
== nothing...
HTH!
Carl.
PS: And 'focus in VID returns nothing too. (;
On 28-Aug-02, Ed Dana wrote:
> OK, so what's going on here.
> I'm trying to put a little error handling around my application. If
<<quoted lines omitted: 43>>
> So what gives? Is this some subtle intricacy of the language, a bug,
> or my normal state of confusion?
--
Carl Read
[4/34] from: lmecir:mbox:vol:cz at: 28-Aug-2002 9:02
Hi Ed,
Rebforce can easily help you.
Try these:
If Error? set/any 'Fred Try [ Print "Get a grip!" ] [ Print
Whatever!
]
If Error? set/any 'Fred Try [ Write %Temp.txt "Yup!" ] [ Print
Whatever!
]
We might call it "a subtle intricacy of the language". This is a feature,
that deserves a lengthy discussion. I would prefer a different behaviour
instead, but the above solution works... The whole trouble is caused by a
situation similar to this:
a: ()
, while this works:
set/any 'a ()
Cheers
-L
----- Original Message -----
From: "Ed Dana" <[EDanaII--Cox--net]>
To: "REBOL List" <[rebol-list--rebol--com]>
Sent: Wednesday, August 28, 2002 4:51 AM
Subject: [REBOL] Help me, Obi Reb Kenobi, you're my only hope!
OK, so what's going on here.
I'm trying to put a little error handling around my application. If it
fails, I need it to send out an alarm. But, depending on the statement,
I get an error when trying to trap the error.
For example, this works as expected:
>> If Error? Fred: Try [ 1 / 0 ] [ Print "Whatever!" ]
Whatever!
As does this:
>> If Error? Fred: Try [ 1 / 1 ] [ Print "Whatever!" ]
== none
This too:
>> If Error? Fred: Try [ Print ] [ Print "Whatever!" ]
Whatever!
But this doesn't:
>> If Error? Fred: Try [ Print "Get a grip!" ] [ Print "Whatever!" ]
Get a grip!
** Script Error: Fred needs a value
** Near: If Error? Fred: Try [Print "Get a grip!"]
This is confusing because why should I get an error on something that
doesn't and shouldn't cause an error.
This works, of course:
>> If Error? Fred: Try [ x: 1 ] [ Print "Whatever!" ]
== none
And this:
>> If Error? Fred: Try [ x: 1 / 0 ] [ Print "Whatever!" ]
Whatever!
And so do these:
>> If Error? Fred: Try [ Do [ 1 / 0 ] ] [ Print "Whatever!" ]
Whatever!
>> If Error? Fred: Try [ Do [ 1 / 1 ] ] [ Print "Whatever!" ]
== none
What's perplexing about the previous two is that it is a "Do" statement
that I am trying to execute and trap. Instead of functioning as above,
it blows up and gives me the "needs a value error".
And curiously, not only does Print fail, but so does Write. And that is
a function that I need error trapping on, if ever there was one.
>> If Error? Fred: Try [ Write %Temp.txt "Yup!" ] [ Print "Whatever!" ]
** Script Error: Fred needs a value
** Near: If Error? Fred: Try [Write %Temp.txt "Yup!"]
I've even tried disarming the error, but to no avail:
>> If Error? Fred: Try [ Write %Temp.txt "Yup!" ] [ Print "Whatever!" ]
Disarm Fred
** Script Error: Fred needs a value
** Near: If Error? Fred: Try [Write %Temp.txt "Yup!"]
So what gives? Is this some subtle intricacy of the language, a bug, or my
normal state of confusion?
--
Sincerely, | Mud can make you prisoner, and the plains can bake
Ed Dana | you dry. Snow can burn your eyes, but only people
Software Developer | make you cry.
1Ghz Athlon Amiga | -- Lee Marvin, Paint Your Wagon.
=========== http://OurWorld.CompuServe.com/Homepages/EDanaII ===========
[5/34] from: jason:cunliffe:verizon at: 28-Aug-2002 2:12
hmmm.. I also be glad if someone can explain this issue well
>> Fred: Try ["hello"]
== "hello"
>> fred
== "hello"
>> Fred: Try [print "hello"]
hello
** Script Error: Fred needs a value
** Near: Fred: Try [print "hello"]
>>
>> ? try
USAGE:
TRY block
DESCRIPTION:
Tries to DO a block and returns its value or an error.
TRY is a native value.
ARGUMENTS:
block -- (Type: block)
>> do [print "hello"]
hello
>> fred: do [print "hello"]
hello
** Script Error: fred needs a value
** Near: fred: do [print "hello"]
>> fred: do ["hello"]
== "hello"
>>
Looks like REBOL is being very consistent.
So RebGurus, how do you interpret "returns its value" in this context?
Which Rebol statements have value?
thanks
./Jason
[6/34] from: louisaturk:coxinet at: 28-Aug-2002 0:51
Hi Ed,
My ISP's mail server went done last night, and I was thus unable to send
this. Someone else has probably already helped you by now, but I'll send
this anyway.
At 07:51 PM 8/27/2002 -0700, you wrote:
>OK, so what's going on here.
>I'm trying to put a little error handling around my application. If it
<<quoted lines omitted: 16>>
>This is confusing because why should I get an error on something that
>doesn't and shouldn't cause an error.
Try returns either a value or error message from the block it evaluates.
print
because it lacks an argument returns an error message, which try passes on
to Fred.
print ["Get a grip!"]
outputs a value to the console (thus fooling you), but actually _returns_
nothing (not even an error message, since there is no error); so try in
turn is unable to put a value into Fred. Rebol therefore cannot proceed
past Fred.
After each of your lines type
fred
to see what fred now contains.
Enable try to actually return something and see what happens:
>> If Error? Try [Fred: "Get a grip!" ] [ Print "Whatever!" ]
== none
>> fred
== "Get a grip!"
>>
At the console type
help <function-name>
If it doesn't say that the function returns something, then it probably
doesn't.
hth,
Louis
[7/34] from: lmecir:mbox:vol:cz at: 28-Aug-2002 17:37
Hi Jason,
even Rebol expressions such as:
try [print "hello"]
or
do [print "hello"]
or
()
yield a Rebol value, which, is of type UNSET!.
Check:
type? try [print "hello"] ; == unset!
or
probe head insert [] try [print "hello"] ; == [unset]
etc. The only trouble with a value of that type is, that you cannot use it
in an expression like:
a: ()
, which fires an error. OTOH, you can use UNSET! type value like this:
set/any 'a ()
probe head insert [] () ; == [unset]
type? () ; == unset!
error? () ; == false
unset? () ; == true
etc. Generally spoken, if your expression can yield an UNSET! type value,
you have to use (set/any 'a ...) instead of (a: ...). The trouble with this
approach is, that in the former case you lose the typo protection you
normally have. If no Rebol expression was allowed to yield an UNSET! type
value, this "problem" wouldn't exist.
----- Original Message -----
From: "Jason Cunliffe" <[jason--cunliffe--verizon--net]>
To: <[rebol-list--rebol--com]>
Sent: Wednesday, August 28, 2002 8:12 AM
Subject: [REBOL] Re: Help me, Obi Reb Kenobi, you're my only hope!
hmmm.. I also be glad if someone can explain this issue well
>> Fred: Try ["hello"]
== "hello"
>> fred
== "hello"
>> Fred: Try [print "hello"]
hello
** Script Error: Fred needs a value
** Near: Fred: Try [print "hello"]
>>
>> ? try
USAGE:
TRY block
DESCRIPTION:
Tries to DO a block and returns its value or an error.
TRY is a native value.
ARGUMENTS:
block -- (Type: block)
>> do [print "hello"]
hello
>> fred: do [print "hello"]
hello
** Script Error: fred needs a value
** Near: fred: do [print "hello"]
>> fred: do ["hello"]
== "hello"
>>
Looks like REBOL is being very consistent.
So RebGurus, how do you interpret "returns its value" in this context?
Which Rebol statements have value?
thanks
./Jason
[8/34] from: edanaii:cox at: 28-Aug-2002 18:33
Carl Read wrote:
>Hee - wasted time on this myself today!
>The problem is that 'print doesn't return a value when 'Fred is
<<quoted lines omitted: 11>>
>See?
>Whatever!
Yes. But the value that I was trying to assign Fred was the error that
was to occur when I attempted my action.
More accurately, I have written a couple of daemons, that execute a
command that I pass to it as a parameter. I wanted the daemon to send
out an email if it could not execute the action it was assigned.
Something like this (where Action is the variable that holds the
statement to be executed:
If Error? Error: Try [ Do Action] [ Send Warning email ]
Realizing that Try is similar to Do, I even used:
If Error? Error: Try [ Action] [ Send Warning email ]
The first executed without issue, making me think that everything was
executing OK; it wasn't. The second gave me the "no value" error.
But this is why I'm confused: If try is to be used to help trap errors,
why does it care if a value is set or not? That's why I pointed out that
I got the error when issuing a "write" command. If anything needed to be
trapped, it was that. How else can I tell if a file is not there, or I
don't have access permission, or the file system is too full, etc?
The above statements, BTW, were taken (in form) from a REBOL manual.
They were text-book examples...
>It's possible to write a function that'll check for nothing returned,
>as the any-type! datatype will accept nothing. ie...
<<quoted lines omitted: 14>>
>>>
>== nothing...
I suppose I could use that technique as part of my error trapping, the
question still remains: why? Error trapping should have to do with
trapping errors, not (just) return values.
--
Sincerely, | Cold Hearted Orb, that rules the night. Removes
Ed Dana | the colours from our sight! Red is gray and
Software Developer | yellow white! But we decide which is right...
1Ghz Athlon Amiga | And which is an illusion!
| -- The Moody Blues, Late Lament.
[9/34] from: carl:cybercraft at: 29-Aug-2002 20:23
On 29-Aug-02, Ed Dana wrote:
> Carl Read wrote:
>> Hee - wasted time on this myself today!
<<quoted lines omitted: 19>>
> Yes. But the value that I was trying to assign Fred was the error
> that was to occur when I attempted my action.
Ah. And thanks to the other responses to your post, (specifically the
ones talking about unset), this might be what you want...
if error? Fred: try [unset? print "OK!"][
Fred: disarm Fred print "Fred reports..." probe Fred
]
That gives...
OK!
== none
and this...
if error? Fred: try [unset? 1 / 0][
Fred: disarm Fred print "Fred reports..." probe Fred
]
Fred reports...
make object! [
code: 400
type: 'math
id: 'zero-divide
arg1: none
arg2: none
arg3: none
near: [unset? 1 / 0]
where: none
]
Okay - a full blown test...
test: [either error? Fred: try [
unset? Harry: switch random 3 [
1 [print "Printing..."]
2 ["Returning a value..."]
3 [1 / 0]
]
][
Fred: disarm Fred
print "Fred reports error near..." print mold Fred/near
][
print ["Harry reports..." Harry]
]]
Doing that block 10 times gives...
>> loop 10 [do test]
Harry reports... Returning a value...
Printing...
Fred reports error near...
[unset? Harry: switch random 3]
Fred reports error near...
[1 / 0]
Harry reports... Returning a value...
Printing...
Fred reports error near...
[unset? Harry: switch random 3]
Fred reports error near...
[1 / 0]
Printing...
Fred reports error near...
[unset? Harry: switch random 3]
Fred reports error near...
[1 / 0]
Harry reports... Returning a value...
Printing...
Fred reports error near...
[unset? Harry: switch random 3]
> More accurately, I have written a couple of daemons, that execute a
> command that I pass to it as a parameter. I wanted the daemon to
<<quoted lines omitted: 3>>
> statement to be executed:
> If Error? Error: Try [ Do Action] [ Send Warning email ]
Hopefully the above is what you need. If not, keep asking. Someone
here will know the answer!
> Realizing that Try is similar to Do, I even used:
> If Error? Error: Try [ Action] [ Send Warning email ]
<<quoted lines omitted: 3>>
> But this is why I'm confused: If try is to be used to help trap
> errors, why does it care if a value is set or not?
It doesn't - your error was outside the 'try block...
>> either error? try [print "x"]["Error!"]["No error!"]
x
== "No error!"
>> either error? Fred: try [print "x"]["Error!"]["No error!"]
x
** Script Error: Fred needs a value
** Near: either error? Fred: try [print "x"]
There'd have to be a special case made to stop 'try causing an error
in such cases - and yes, there probably should be.
Writing the above made me think about an error-trap within an
error-trap. So, an alternative to the first test...
test2: [
either error? try [
if error? Fred: try [
switch random 3 [
1 [print "Printing..."]
2 ["Returning something..."]
3 [1 / 0]
]
][
print "Error!" Fred: disarm Fred
]
][
print "Fred Error!" ; ie, Fred unset.
][
print ["Fred reports..." probe Fred]
]
]
Not the same output as the first test though...
>> loop 10 [do test2]
Returning something...
Fred reports... Returning something...
Returning something...
Fred reports... Returning something...
Printing...
Fred Error!
Printing...
Fred Error!
Returning something...
Fred reports... Returning something...
Error!
make object! [
code: 400
type: 'math
id: 'zero-divide
arg1: none
arg2: none
arg3: none
near: [1 / 0]
where: 'switch
]
Fred reports... ?object?
Printing...
Fred Error!
Returning something...
Fred reports... Returning something...
Returning something...
Fred reports... Returning something...
Returning something...
Fred reports... Returning something...
--
Carl Read
[10/34] from: tomc:darkwing:uoregon at: 29-Aug-2002 0:31
On Wed, 28 Aug 2002, Ed Dana wrote:
> Yes. But the value that I was trying to assign Fred was the error that
> was to occur when I attempted my action.
you capture that error from 'try
>> either error? err: try[1 / 0 ][true][false]
== true
>> err
** Math Error: Attempt to divide by zero
** Near: 1 / 0
>> either error? err: try[1 / 1][true][false]
== false
>> err
== 1
> More accurately, I have written a couple of daemons, that execute a
> command that I pass to it as a parameter. I wanted the daemon to send
<<quoted lines omitted: 4>>
> Realizing that Try is similar to Do, I even used:
> If Error? Error: Try [ Action] [ Send Warning email ]
been doing something similar daily for years
should not be a problem
> The first executed without issue, making me think that everything was
> executing OK; it wasn't. The second gave me the "no value" error.
<<quoted lines omitted: 3>>
> trapped, it was that. How else can I tell if a file is not there, or I
> don't have access permission, or the file system is too full, etc?
I agree that current behavior does not lead me down the path of least
astonishment.
I would expect err: try[prin ""] to pass quietly
and 'err to have the value it would have after a unset 'err
that is:
>> error? unset 'err
== false
prolly should send it to feedback.
however as a umm.. hack! you could add a constant (anything but an error!)
to the end of your 'try block 'try will return the constant if it gets to
it without encountering an error first.
err: none either error? err: try[ (1 / 0 ) "no-err"][true][false]
== true
>> err
** Math Error: Attempt to divide by zero
** Near: 1 / 0
>> err: none either error? err: try[ (print 1 ) "no-err"][true][false]
1
== false
>> err
== "no-err"
>> err: none either error? err: try[ (1 ) "no-err"][true][false]
== false
>> err
== "no-err"
>> either error? err: try[ make error! "boo" "no-err"][true][false]
== true
>> err
** User Error: boo
** Near: make error! "boo" "no-err"
[11/34] from: lmecir:mbox:vol:cz at: 29-Aug-2002 10:06
Hi Ed,
it looks, that you missed my advice on this.
<<Ed>>
...
>>>If Error? try [Fred: Print "See?"][Print "Whatever!"]
>>>
>See?
>Whatever!
>
Yes. But the value that I was trying to assign Fred was the error that
was to occur when I attempted my action.
More accurately, I have written a couple of daemons, that execute a
command that I pass to it as a parameter. I wanted the daemon to send
out an email if it could not execute the action it was assigned.
Something like this (where Action is the variable that holds the
statement to be executed:
If Error? Error: Try [ Do Action] [ Send Warning email ]
Realizing that Try is similar to Do, I even used:
If Error? Error: Try [ Action] [ Send Warning email ]
The first executed without issue, making me think that everything was
executing OK; it wasn't. The second gave me the "no value" error.
But this is why I'm confused: If try is to be used to help trap errors,
why does it care if a value is set or not? That's why I pointed out that
I got the error when issuing a "write" command. If anything needed to be
trapped, it was that. How else can I tell if a file is not there, or I
don't have access permission, or the file system is too full, etc?
<</Ed>>
<<L>>
the situation is simpler than you think. You can use:
if error? set/any 'error try action [send warning email]
Try doesn't care what is the result value. Your problem is, that if you use
an expression like (error: ...), the interpreter fires an error, if the
result of the (...) expression is of the UNSET! datatype. This means, that
the error occurs outside of the try block, which means, that TRY cannot trap
it.
<</L>>
<<Ed>>
...
The above statements, BTW, were taken (in form) from a REBOL manual.
They were text-book examples...
<</Ed>>
<<L>>
yes, there are some misleading informations in the documentation...
<</L>>
<<Ed>>
I suppose I could use that technique as part of my error trapping, the
question still remains: why? Error trapping should have to do with
trapping errors, not (just) return values.
<</Ed>>
<<L>>
you can, you just need to know how and why...
<</L>>
Cheers
-L
[12/34] from: carl:cybercraft at: 30-Aug-2002 10:48
On 29-Aug-02, Tom Conlin wrote:
> err: none either error? err: try[ (1 / 0 ) "no-err"][true][false]
> == true
<<quoted lines omitted: 17>>
> ** Near: make error! "boo" "no-err"
>>>
And that's probably the best way to do it, and certainly simpler than
my approach...
--
Carl Read
[13/34] from: edanaii:cox at: 29-Aug-2002 17:23
Ladislav Mecir wrote:
>Hi Ed,
>
>it looks, that you missed my advice on this.
>
I didn't miss your advice, Ladislav. Yesterday was a busy day so I kinda
read through it quickly. Sorry for that.
I tried the solution you presented below, it worked great.
Thanks to all for the input.
Personally, I would call it a quirk, but every language has its quirks, why should REBOL
be any different. :)
--
Sincerely, | Life is pain, Highness. Anyone who says
Ed Dana | differently is selling something.
Software Developer | -- The Princess Bride.
1Ghz Athlon Amiga |
[14/34] from: ammon:rcslv at: 30-Aug-2002 21:45
Hi,
The other suggestions will probably bring you to realise this, but I
wanted to make it a little more obvious...
When attempting to catch an error and disarm it for your own error handling
scheme you will find that using 'set/any is needed rather than a set-word
for maximum strength error handling. For example:
Use
>> if error set/any fred try [print "done"] [print "Error!"]
done
>>
Rather than
>> if error fred: try [print "done"] [print "Error!"]
All that try does is catches any error that may be encountered and returns
it in as an Error! datatype. 'try doesn't care if a datatype that cannnot
be assigned via 'set or a set-word is passed, it will only attempt to
'disarm an error within the argument passed to it.
HTH
Ammon
[15/34] from: lmecir:mbox:vol:cz at: 31-Aug-2002 10:58
Hi all,
<<Ed>>
...
Personally, I would call it a quirk, but every language has its quirks, why
should REBOL be any different. :)
<</Ed>>
I call it a quirk too and I suggested to straighten the things some time
ago. Meanwhile I use my DEFAULT function:
default action error-handling
The source of the function is:
Rebol [
Title: "Default"
File: %default.r
Author: "Ladislav Mecir"
Email: [lmecir--mbox--vol--cz]
Reb: reb://Sites/Ladislav
Web: http://www.rebolforces.com/~ladislav
Purpose: {
An error handling function
}
Category: [General]
]
default: function [
{
Try to evaluate code.
Evaluate the fault block,
if an error occurs
}
[throw]
code [block!]
fault [block!]
/good pass [block!]
] [result] [
either error? set/any 'result try code [
use [error] compose [
any-type? error: :result
do (reduce [fault])
]
] [
either good [do pass] [get/any 'result]
]
]
[16/34] from: g:santilli:tiscalinet:it at: 31-Aug-2002 15:56
Hi Ladislav,
On Saturday, August 31, 2002, 10:58:41 AM, you wrote:
LM> Meanwhile I use my DEFAULT function:
BTW Ladislav, do you think there could be any problems with this
alternative version?
default: func [
[throw]
code [block!]
fault [block!]
/good pass [block!]
/local result
] [
either error? set/any 'result try code [
fault: func [[throw] error [error!]] fault
fault result
] [
do any [pass [get/any 'result]]
]
]
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r
[17/34] from: lmecir:mbox:vol:cz at: 31-Aug-2002 20:28
Hi Gabriele,
<<G>>
...
BTW Ladislav, do you think there could be any problems with this
alternative version?
default: func [
[throw]
code [block!]
fault [block!]
/good pass [block!]
/local result
] [
either error? set/any 'result try code [
fault: func [[throw] error [error!]] fault
fault result
] [
do any [pass [get/any 'result]]
]
]
<</G>>
I think, that your version is more understandable and more robust. That is
why I suggest others to use Gabriele's version instead of mine.
I am still curious, if many Rebol users prefer to allow UNSET! valued
expressions (eventually why?).
OTOH, both versions of DEFAULT cannot discern "illegal" and "legal" errors,
which is another glitch in Rebol I would prefer to have straightened.
Ciao
-L
[18/34] from: g:santilli:tiscalinet:it at: 1-Sep-2002 12:06
Hi Ladislav,
On Saturday, August 31, 2002, 8:28:43 PM, you wrote:
LM> I am still curious, if many Rebol users prefer to allow UNSET! valued
LM> expressions (eventually why?).
There's no reason to have them, and that's just likely to be an
implementation issue with the current interpreter (it needs unset!
for unset words, and once you have that is pretty natural to have:
>> f: func [] [return]
return unset!, being RETURN's argument unset; so they have
probably decided that empty blocks should have returned unset!
too...)
LM> OTOH, both versions of DEFAULT cannot discern "illegal" and "legal" errors,
LM> which is another glitch in Rebol I would prefer to have straightened.
I was looking in your site to see what you intend for an illegal
error, but I wasn't able to find it.
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r
[19/34] from: lmecir:mbox:vol:cz at: 1-Sep-2002 13:23
Hi Gabriele and all,
LM> I am still curious, if many Rebol users prefer to allow UNSET! valued
LM> expressions (eventually why?).
<<Gabriele>>
There's no reason to have them, and that's just likely to be an
implementation issue with the current interpreter (it needs unset!
for unset words, and once you have that is pretty natural to have:
>> f: func [] [return]
return unset!, being RETURN's argument unset; so they have
probably decided that empty blocks should have returned unset!
too...)
<</Gabriele>>
<<L>>
You are right, it looks logical at a first glance. Nevertheless, the
following looks logical too:
type? while [false] [] ; == none!
and it differs from
type? do [] ; == unset!
I think, that the behaviour should be unified. My proposition is to use the
former convention, which is much less complicated.
I am not against using UNSET! values internally for the interpreter purposes
(detection of uninitialized variables). OTOH, this purpose is totally
internal and shouldn't be "exposed" to the user.
A similar "quirk" with an END! type value has already been straightened by
RT.
<</L>>
LM> OTOH, both versions of DEFAULT cannot discern "illegal" and "legal"
errors,
LM> which is another quirk in Rebol I would prefer to have straightened.
<<Gabriele>>
I was looking in your site to see what you intend for an illegal
error, but I wasn't able to find it.
<</Gabriele>>
<<L>>
It is my fault, I wrote it too lazily. Here is a more thorough explanation:
block: []
probe disarm try [first block]
; == make object! [
; code: 315
; type: 'script
; id: 'past-end
; arg1: none
; arg2: none
; arg3: none
; near: [first block]
; where: none
; ]
The result of the (first block) expression evaluation doesn't exist in a
sense. Try "creates" its result catching the fired error you see above.
Now a more complicated code sample:
block2: head insert tail copy [] try [first block]
probe disarm try [first block2]
The difference is, that in this case the result of the (first block2)
expression evaluation "legally" exists, that is why I call it a "legal"
error.
A function like TRY cannot discern these cases, while a native version of
the DEFAULT function could.
Ciao
-L
[20/34] from: g:santilli:tiscalinet:it at: 1-Sep-2002 19:26
Hi Ladislav,
On Sunday, September 1, 2002, 1:23:35 PM, you wrote:
LM> The difference is, that in this case the result of the (first block2)
LM> expression evaluation "legally" exists, that is why I call it a "legal"
LM> error.
I see. I'd more likely have errors as first class, instead of a
DEFAULT function able to make the distinction. Anyway, it is
possible to discern the two cases with:
>> is-really-error?: func [code] [error? try compose [error? (code)]]
>> is-really-error? [first block]
== true
>> is-really-error? [first block2]
== false
I haven't tried it with any other case tough.
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r
[21/34] from: lmecir:mbox:vol:cz at: 1-Sep-2002 20:28
Hi again,
LM> The difference is, that in this case the result of the (first block2)
LM> expression evaluation "legally" exists, that is why I call it a "legal"
LM> error.
<<Gabriele>>
I see. I'd more likely have errors as first class, instead of a
DEFAULT function able to make the distinction. Anyway, it is
possible to discern the two cases with:
>> is-really-error?: func [code] [error? try compose [error? (code)]]
>> is-really-error? [first block]
== true
>> is-really-error? [first block2]
== false
I haven't tried it with any other case tough.
<</Gabriele>>
It looks to me, that the "first class error" and the "legal vs. illegal
error" distinction are two sides of the same coin.
Your IS-REALLY-ERROR? function works for simple code like above, but, AFAIK,
we cannot handle all possible cases, like e.g.:
is-really-error? [1 first block2] ; == true
(until errors will be "first class").
Ciao
-L
[22/34] from: g:santilli:tiscalinet:it at: 2-Sep-2002 0:39
Hi Ladislav,
On Sunday, September 1, 2002, 8:28:22 PM, you wrote:
LM> It looks to me, that the "first class error" and the "legal vs. illegal
LM> error" distinction are two sides of the same coin.
Indeed. We cannot use errors at all, only disarm them. So,
probably we can state that errors can never be "legal", if we
decide that we should never intentionally return an (armed) error.
(It can be seen as a sort of workaround...)
LM> Your IS-REALLY-ERROR? function works for simple code like above, but, AFAIK,
LM> we cannot handle all possible cases, like e.g.:
The problem is that if you enclose the code in a block or a paren
the error is immediately fired; i.e. the only way to return an
error from an expression is if the expression is being evaluated
directly as an argument for a function. This makes me think that
it's likely that this was added as a way to make functions like
DISARM and ERROR? work, but otherwise error!s were intended as a
very special class of values.
I am more and more tempted to start writing a REBOL
implementation, just to try out different approaches and to better
understand why things have been done this way... pity I don't
really have the time to do it.
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r
[23/34] from: rotenca:telvia:it at: 2-Sep-2002 2:36
Hi Ladislav and Gabriele,
> Your IS-REALLY-ERROR? function works for simple code like above, but, AFAIK,
> we cannot handle all possible cases, like e.g.:
>
> is-really-error? [1 first block2] ; == true
>
> (until errors will be "first class").
You are right about first class, but i think the code above gives the correct
result in the actual implementation of Rebol, because, for example, the
execution of the block:
[x: 1 first block2 x: 2]
is interrupted with a real error when the expression "first block2" is
executed, and "x: 2" is never executed:
do [x: 1 first block2 x: 2]
x ; == 1
so this is a real error in the actual Rebol implementation.
I think, indeed, that is not correct to return false with:
is-really-error? [first block2] ;==false
for the same reason. The function should answer to this question:
"the code fires an error when evaluated?"
and [first block2] fires an error when evaluated.
While the expression:
[type? first block2]
does not fires an error when evaluated
I think there is no difference from this point of view between
[first block] -> error
[first block2] -> error
but there is a difference between
[type? first block] -> error
[type? first block2] -> not error
And Try is enough to discern them.
Is-really-error? should be called:
can-some-functions-accept-this-argument-without-an-error?
and the blocks
[first block2]
can be accepted by many functions if not evaluated, but when you do it, before
passing the result to a function, it always fires an error!
BTW, actual implementation fails with
is-really-error? first block2 ;== *** error!
but can be corrected.
---
Ciao
Romano
[24/34] from: lmecir:mbox:vol:cz at: 2-Sep-2002 8:58
Hi Romano,
no objection to your analyse. The fact, that the expression (first block2)
is illegal, while (error? first block2) isn't justifies my POV, that this
behaviour is a Rebol quirk. I want the interpreter/language to be less
aggressive (and faster and simpler and logical ...).
I am saying the same about the "exposition" of the UNSET! datatype, and I
was saying it about the "exposition" of the END! datatype, but the last one
got straightened.
<<Romano>>
Hi Ladislav and Gabriele,
> Your IS-REALLY-ERROR? function works for simple code like above, but,
AFAIK,
> we cannot handle all possible cases, like e.g.:
>
> is-really-error? [1 first block2] ; == true
>
> (until errors will be "first class").
You are right about first class, but i think the code above gives the
correct
result in the actual implementation of Rebol, because, for example, the
execution of the block:
[x: 1 first block2 x: 2]
is interrupted with a real error when the expression "first block2" is
executed, and "x: 2" is never executed:
do [x: 1 first block2 x: 2]
x ; == 1
so this is a real error in the actual Rebol implementation.
I think, indeed, that is not correct to return false with:
is-really-error? [first block2] ;==false
for the same reason. The function should answer to this question:
"the code fires an error when evaluated?"
and [first block2] fires an error when evaluated.
While the expression:
[type? first block2]
does not fires an error when evaluated
I think there is no difference from this point of view between
[first block] -> error
[first block2] -> error
but there is a difference between
[type? first block] -> error
[type? first block2] -> not error
And Try is enough to discern them.
Is-really-error? should be called:
can-some-functions-accept-this-argument-without-an-error?
and the blocks
[first block2]
can be accepted by many functions if not evaluated, but when you do it,
before
passing the result to a function, it always fires an error!
BTW, actual implementation fails with
is-really-error? first block2 ;== *** error!
but can be corrected.
---
Ciao
Romano
[25/34] from: lmecir:mbox:vol:cz at: 2-Sep-2002 10:19
Hi Gabriele, Romano, myself and others,
when I said:
<<L>>
IS-REALLY-ERROR? function works for simple code like above, but, AFAIK, we
cannot handle all possible cases, like e.g.:
is-really-error? [1 first block2] ; == true
(until errors will be "first class")"
<</L>>
, I was wrong. Here is a (complicated, but working) version of the DEFAULT
function, that can handle it:
do http://www.rebolforces.com/~ladislav/highfun.r
default2: transp-func [
code [block!]
fault [block!]
/good pass [block!]
/local result error code2
] [
transp-while [not tail? code] [
code: if error? set/any 'error try [
set/any 'code2 second do/next compose [
error? set/any 'result (code)
]
skip code (index? code2) - 3
] [tail code]
]
either error? get/any 'error [
fault: func [[throw] error [error!]] fault
local-return fault error
] [
do any [pass [local-return get/any 'result]]
]
]
block2: head insert copy [] try [first []]
default2/good [first block2 1] ["error"] ["pass"] ; == "pass"
default2/good [first block2] ["error"] ["pass"] ; == "pass"
default2/good [first []] ["error"] ["pass"] ; == "error"
Ciao
Ladislav
[26/34] from: lmecir:mbox:vol:cz at: 2-Sep-2002 10:31
Correction, I posted a wrong version, so once again:
do http://www.rebolforces.com/~ladislav/highfun.r
default2: transp-func [
code [block!]
fault [block!]
/good pass [block!]
/local result error code2
] [
transp-while [not tail? code] [
if error? set/any 'error try [
code2: second do/next compose [
error? set/any 'result (code)
]
code: skip code (index? code2) - 3
] [code: tail code]
]
either error? get/any 'error [
fault: func [[throw] error [error!]] fault
fault error
] [
do any [pass [local-return get/any 'result]]
]
]
block2: head insert copy [] try [first []]
default2/good [first block2 1] ["error"] ["pass"] ; == "pass"
default2/good [first block2] ["error"] ["pass"] ; == "pass"
default2/good [first []] ["error"] ["pass"] ; == "error"
Ciao
Ladislav
[27/34] from: rotenca:telvia:it at: 2-Sep-2002 13:38
Hi Ladislav and all,
>, I was wrong. Here is a (complicated, but working) version of the DEFAULT
>function, that can handle it:
I also was experimenting with do/next and this is my code. It try to handle
also return, throw, break.
isr?: function [blk [block!]][res][
while [not tail? blk][
either error? try [
error? catch [
error? do does [
error? loop 1 [
error? set 'res do/next compose [error? (blk)]
]
]
]
][
return true
][
if none? res [prin "control detected " return false]
blk: second res
res: none
]
]
false
]
block2: head insert tail copy [] try [first []]
isr? [1 2 first block2 3] ;==false
isr? [1 2 first block 3] ;==true
isr? [1 2 throw first block2 3] ;==control detected false
isr? [1 2 throw first block 3] ;==true
isr? [1 2 return first block2 3] ;==control detected false
isr? [1 2 return first block 3] ;==true
isr? [1 2 break/return first block2 3] ;==control detected false
isr? [1 2 break/return first block 3] ;==true
---
Ciao
Romano
[28/34] from: lmecir:mbox:vol:cz at: 2-Sep-2002 15:11
Hi Romano,
<<Romano>>
...
I also was experimenting with do/next and this is my code. It try to handle
also return, throw, break.
isr?: function [blk [block!]][res][
while [not tail? blk][
either error? try [
error? catch [
error? do does [
error? loop 1 [
error? set 'res do/next compose [error? (blk)]
]
]
]
][
return true
][
if none? res [prin "control detected " return false]
blk: second res
res: none
]
]
false
]
block2: head insert tail copy [] try [first []]
isr? [1 2 first block2 3] ;==false
isr? [1 2 first block 3] ;==true
isr? [1 2 throw first block2 3] ;==control detected false
isr? [1 2 throw first block 3] ;==true
isr? [1 2 return first block2 3] ;==control detected false
isr? [1 2 return first block 3] ;==true
isr? [1 2 break/return first block2 3] ;==control detected false
isr? [1 2 break/return first block 3] ;==true
<</Romano>>
1a) THROW. My DEFAULT2 function "works" as follows:
default2/good [1 2 throw first block2 3] ["caught"] ["passed"]
** Throw Error: ** Script Error: Out of range or past end
** Near: first []
i.e. it isn't able to catch this kind of error. The ISR? function seems to
not notice there was an error.
1b) However:
type? catch [default2/good [1 2 throw first block2 3] ["caught"]
["passed"]] ; == error!
, i.e. DEFAULT2 works as expected in this case.
type? catch [isr? [1 2 throw first block2 3]] ; control detected ==
logic!
, i.e. the ISR? function "creates" an artifact.
For RETURN and BREAK I obtained equivalent results.
I would prefer to have the ability to catch even BREAK, RETURN and THROW
errors, which I cannot do now (AFAIK!).
Ciao
Ladislav
[29/34] from: rotenca:telvia:it at: 2-Sep-2002 18:08
Hi Ladislav,
> 1a) THROW. My DEFAULT2 function "works" as follows:
>
> default2/good [1 2 throw first block2 3] ["caught"] ["passed"]
> ** Throw Error: ** Script Error: Out of range or past end
> ** Near: first []
>
> i.e. it isn't able to catch this kind of error. The ISR? function seems to
> not notice there was an error.
[...]
> , i.e. the ISR? function "creates" an artifact.
>
> For RETURN and BREAK I obtained equivalent results.
I wanted to catch throw (without catch), return (out of function) and break
(out of a loop).
I left to the user what to do with them.
If you think they must be errors in the Default function, the isr? func should
return true:
if none? res [return true]
instead of
if none? res [prin "control detected " return false]
> I would prefer to have the ability to catch even BREAK, RETURN and THROW
> errors, which I cannot do now (AFAIK!).
If one wants the throw/break/return error! object in the isr? function, he
must re-create it :-(
But attention, the no-loop error is a special error. If this is standard:
error? do does [return make error! [throw no-function]] ;== true
this is not:
>> error? do does [return make error! [throw no-loop]]
** Throw Error: Nothing to break
** Near: return make error! [throw no-loop]
The break error! is third class! :-)
> Ciao
> Ladislav
---
Ciao
Romano
[30/34] from: anton:lexicon at: 3-Sep-2002 5:13
I'm glad you guys are sorting all this
stuff out, because I don't know what you
are on about half the time. :)
You have encouraged me to learn something
new for today - that is using do/next.
I never really looked into it before.
Probably because I couldn't think of a use
for it.
Anyway, for other newbies to do/next, here's
how to step through some code, one expression
at a time.
code: [print 1 print 2 print 3]
loop 3 [
code: second do/next code
]
Cool! Now to think of a use for it...
Anton.
[31/34] from: lmecir:mbox:vol:cz at: 3-Sep-2002 9:32
Hi all,
I thank Romano for his finding and try to comprise out knowledge about Rebol
errors.
We can classify errors by the interpreter behaviour to three groups:
1) crashes (errors, that crash the interpreter). I think, that such errors
shouldn't exist at all. (Opinions?)
1a) Native function crashes, like SAME? crash, where it is enough to modify
the function - my IDENTICAL? doesn't crash. (I don't understand, why this
crash still persists?!)
1b) "Self-modifying" code crashes - there is only one recipe to "cure"
this - rewrite the interpreter, i.e. use a slightly different interpretation
strategy. An example of such crash is:
a: func [x] [1]
a a: 1
This crash has already been "cured", but the behaviour still is strange -
compare it to the Freebell interpreter's behaviour, where the above code
isn't self-modifying at all! These crashes can be eliminated - e.g. using a
strategy I proposed. (Opinions?)
2) Errors are representable by Rebol values which don't crash the
interpreter.
2a) Errors, that cannot be caught. Examples are THROW ERRORS caused by
RETURN or EXIT out of function, THROW out of a catch block or BREAK out of a
loop. I think, that the interpreter should be modified to be able to catch
these. (Opinions?)
2b) "Normal" errors, that can be caught by the TRY function (or my
DEFAULT/DEFAULT2).
Another possibility is to classify errors by aggressivity of their
evaluation. Almost every error is second class like:
II)
type? make error! "" ; == error!
, which is OK, but:
type? (make error! "")
** User Error:
** Near: make error! ""
doesn't yield the same result as the former expression, which is an
interpreter quirk. I propose to change all errors to first class, which
would be:
I) Hypothetical!
type? (make error! "") ; == error!
III) Romano revealed, that some errors are third class, like:
type? make error! [throw no-loop]
** Throw Error: Nothing to break
** Near: type? make error! [throw no-loop]
, which is a bigger quirk than above.
Opposite opinions welcome
Cheers
Ladislav
[32/34] from: rotenca:telvia:it at: 3-Sep-2002 13:05
Hi Ladislav,
thank for your summary, only a note about:
> type? make error! [throw no-loop]
> ** Throw Error: Nothing to break
> ** Near: type? make error! [throw no-loop]
>
> , which is a bigger quirk than above.
no-loop error! seems to have the same beaviour which has any others error,
when a function has at least the attribute []:
>> error? do func[][return make error! "any"] ;== true
>> error? do func[[]][return make error! "any"]
** Throw Error: Return or exit not in function
** Where: func [[]][return make error! "any"]
** Near: return make error! "any"
---
Ciao
Romano
> Opposite opinions welcome
> Cheers
<<quoted lines omitted: 3>>
> [rebol-request--rebol--com] with "unsubscribe" in the
> subject, without the quotes.
---
Ciao
Romano
[33/34] from: lmecir:mbox:vol:cz at: 3-Sep-2002 14:49
Hi Romano,
the behaviour seems to have more to do with function attributes:
<<Romano>>
...
no-loop error! seems to have the same beaviour which has any others error,
when a function has at least the attribute []:
>> error? do func[][return make error! "any"] ;== true
>> error? do func[[]][return make error! "any"]
** Throw Error: Return or exit not in function
** Where: func [[]][return make error! "any"]
** Near: return make error! "any"
<</Romano>>
See the following code samples:
type? do does [type? do func [] [return make error! ""]] ; == datatype!
type? do does [type? do func [[throw]] [return make error! ""]] ; ==
error!
type? do does [type? do func [[]] [return make error! ""]] ; == error!
The empty attribute is interpreted like the [throw] attribute in this case!
It looks like an implementation issue.
Ciao
Ladislav
[34/34] from: rotenca:telvia:it at: 3-Sep-2002 16:19
Hi Ladislav,
> the behaviour seems to have more to do with function attributes:
> See the following code samples:
<<quoted lines omitted: 3>>
> The empty attribute is interpreted like the [throw] attribute in this case!
> It looks like an implementation issue.
Yes, we spoke about that some time ago.
But my previous statement:
no-loop error! seems to have the same beaviour which has any others error,
when a function has at least the attribute []:
is wrong: no-loop is uncatchable at all, and undisarmable, while orthers
errors in functions with the attribute [] or [throw] can be catched and
disarmed with a function wrapper.
BTW, no-loop is the only one error wich show this behaviour. Neither Syntax
error have its behaviour.
I think that this could be related to the Break behaviour which ignores
functions bound:
loop 2 [print 1 do does [break]] ;= 1
Break does not requires [throw] to throw the break to the upper function. So a
Break error can only happens at the higher level of code execution and never
inside user code.
> Ciao
> Ladislav
---
Ciao
Romano
Notes
- Quoted lines have been omitted from some messages.
View the message alone to see the lines that have been omitted