TAKE vs. TRY TAKE: Best of Both Worlds!

Experiments at being prescriptive in early Ren-C worried that getting back a NULL might not be enough to warn you about a misunderstanding from the result of TAKE.

So we wound up with TAKE* as distinct from TAKE:

ren-c>> take []
** Error: TAKE-ing from an empty block, use TAKE*

ren-c>> take* []
; null

But this became a textbook case of using TAKE with TRY, under the new definitional-error-powered conception:

>> block: []

>> take block
** Error: TAKE-ing from an empty block, if intentional use TRY TAKE

>> try take block
== \~null~\  ; antiform

Having functions return ERROR! instead of returning NULL is a good way of throwing in a "speedbump" to catch situations that are likely to be mistakes...with the simple answer of adding in a TRY if you want to get past the speedbump (or use EXCEPT to catch the error).

TAKE is a small example, but there are much more consequential ones!

See for instance: changing PARSE to return ERROR! if it couldn't process the rules and get to the end of input

2 Likes

Quick Recap Of What's Wrong With Rebol2/Red/R3-Alpha

If you tried to make TAKE cause an error in Rebol2/R3-Alpha/Red, you would have to trap it via the closest thing they have to Ren-C's TRY (called ATTEMPT) which would put the call in a block:

rebol2>> attempt [take []]
== #[none]

But this would be very dangerous, as it would trap errors that weren't being emitted specifically by the TAKE. For instance, a typo:

 rebol2>> block: [a b c]

 rebol2>> attempt [take blockk]  ; typo
 == #[none]

Or it would gloss over a variable being of the wrong type:

 rebol2>> data: 1020

 rebol2>> attempt [take data]  ; taking an integer!
 == #[none]

These are simple examples, but there's no limit to how dangerous this is.

For more: Rebol2's "Hot Errors" (Abandoned by R3-Alpha, Red)

1 Like