What Are Definitional Returns?

Novices using Rebol2 or Red aren't really clear on how their RETURN works. (Or doesn't work, as the case my be.) RETURN climbs the stack until it finds a function that is willing to accept returns.

  • Functions in Rebol2/Red that won't accept returns: IF, WHILE, or pretty much any native
  • Functions in Rebol2/Red that will accept returns: any user FUNC you write

To give a brutally simple example, you cannot implement UNLESS in terms of IF:

 rebol2>> foo: func [x] [if not x = 10 [return "not 10"] return "it's 10!"]
 rebol2>> foo 20
 == "not 10"

 rebol2>> unless: func [cond block] [if not cond block]
 rebol2>> bar: func [x] [unless x = 10 [return "not 10"] return "it's 10!"]
 rebol2>> bar 20
 == "it's 10"  ; D'oh

That UNLESS, because it's a FUNC and not a native, is a candidate for receiving RETURN. So the UNLESS itself returned "not 10" instead of returning from bar. Execution continued and the `return "it's 10!" ran. I maintain that correct behavior constitutes another must-have, and I was by no means alone in this, nor the first to say so.

>> unless: function [cond block] [if not cond (block)]  ; see note re: group!
>> bar: function [x] [unless x = 10 [return "not 10"] return "it's 10!"]
>> bar 20
== "not 10"

I do not consider annotating UNLESS to say "I'm the kind of thing that doesn't catch returns" to be remotely acceptable. I'd sooner throw out the project than go that route. Addressing definitional returns wasn't at all trivial...even though conceptually it was understood what needed to be done. It was one of the first things I tried to do in open-sourced R3-Alpha. The rearranging I had to do in order to understand the code well enough to accomplish it laid the groundwork for many features to come.

(Note: The reason you have to put a group! around block (or say :block) is due to soft-quoted branching, and I argue for the tradeoff here. I would not consider that one of my non-negotiable points for this list, though I've offered what I believe to be some compelling arguments. I do--however--consider FUNCTION instead of FUNC to be a non-negotiable way of writing this, with current leaning that FUNC is a full synonym for FUNCTION)