Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

[REBOL] Re: Pre-REP on NONE! and SERIES! polymorphism

From: lmecir:mbox:vol:cz at: 14-Jun-2002 8:49

Hi all, this is a thing loosely connected to the subject. I wrote a DEFAULT function (may be of some use for error handling). default: function [ { try to evaluate code and then 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] ] ] Here is a comparison of its behaviour with the functions contained in Core 2.5: ex1: function [[catch]] [r] [ set/any 'r throw-on-error a do b ] ex2: function [[catch]] [r] [ if none? set/any 'r attempt a [ throw make error! "error" ] do b ] ex3: function [[catch]] [r] [ set/any 'r default a [throw error] do b ] a: [return "OK"] b: ["KO"] ex1 ; == "KO" ex2 ; == "OK" ex3 ; == "KO" a: [()] b: [if not value? 'r ["OK"]] ex1; ** Script Error: blk needs a value ; ** Where: throw-on-error ex2 ; == "OK" ex3 ; == "OK" The above tests show that both THROW-ON-ERROR as well as ATTEMPT should be corrected. I suggest to write them as follows: throw-on-error: func [ {Evaluates a block, which if it results in an error, throws that error.} [throw] blk [block!] ][ if error? set/any 'blk try blk [throw blk] get/any 'blk ] attempt: func [ {Tries to evaluate and returns result or NONE on error.} [throw] value ][ if not error? set/any 'value try :value [get/any 'value] ] Sometimes we need to distinguish between a pass value and a default value. See the following example: attempt [none] ; == none attempt [1 / 0] ; == none In the first case NONE is a pass value, while in the second one, it is a default value. Compare that to: default/good [none] ["default"] ["pass"] default/good [1 / 0] ["default"] ["pass"] This is an Achilles' heel of the ATTEMPT function and of any function that uses NONE as a default value in the cases when NONE can be a pass value too. The same problem exists with errors. An error can be a pass value as in: a: head insert [] make error! "OK" first a ; ** User Error: OK ; ** Near: a: head insert [error] make , if A is a block containing an error value at its first position and it can be a default value like in 1 / 0 ; ** Math Error: Attempt to divide by zero ; ** Near: 1 / 0 We can distinguish these cases as follows: error? first a ; == true error? 1 / 0 ; ** Math Error: Attempt to divide by zero ; ** Near: error? 1 / 0 The TRY function cannot discern these cases and therefore we do not have any general function able to do that. The DEFAULT function isn't working as I would like it to work, because it uses the TRY function. A few questions: - Should Rebol have a native version of the DEFAULT function able to discern the default and pass cases? - Should the behaviour of error values change a bit to enable the interpreter to yield errors as pass values? - Should we have versions of PICK, SELECT, etc. functions discerning the pass and default cases? An unrelated note: The usage of NONE in place of an empty block is not a Rebol rule. There are cases, when Rebol returns an empty block: exclude [a] [a b] ; == [] -L