|Version||alpha 31||Category||Unspecified||Submitted by||BrianH|
|Summary||No [throw] attribute: Mezzanine control functions capture RETURN and EXIT|
The USE mezzanine needs to add the R3 equivalent of the R2 [throw] function attribute to the closure it creates and executes. What is the new way of specifying this in function specs?
This also affects DO of string/file/url (#904), MODULE and MAKE module! (both), CONTEXT, OBJECT, COLLECT, DP and DT, FIND-ALL (#1718), the proposed ANY-OF and ALL-OF (#637) and KEEP-EACH (#1733), and all other potential mezzanine control and loop functions.
|Assigned to||n/a||Fixed in||-||Last Update||10-May-2015 08:52|
There needs to be some equivalent to the R2 [throw] function attribute, and this should be discussed in R3 chat.
This bug and #447 are significant regressions compared to R2.
The lack of a [throw] attribute or some R3 equivalent is blocking every potential mezzanine control or loop function.
Changed severity to: block.
Changed the ticket to better reflect the scope of the problem. There is a discussion of possible solutions to this problem here: http://www.rebol.com/r3/notes/errors.html
The COLLECT and USE functions are particularly interesting because they are affected by this bug in two different ways in the same function. The proposal to make RETURN and EXIT be bound to a scope at function creation time would solve the problem with the outer function in COLLECT or USE, but still cause a problem for their inner functions.
|in the core-tests suite|
|I do agree that this is blocking. Until resolved R3 should not turn beta in my opinion.|
There has been one advantage to this: It is forcing us to change control functions into native code. That makes R3 faster, and it's not that big a deal when R3 is open source (it was a really big problem before then). Not saying that we shouldn't fix this, just that it accidentally has one good side effect.
Btw, Carl has made it clear that we are unlikely to get the same syntax for this option, since he wants to switch to using set-words for these kinds of function options, like return: is used for routines in R2. Also, the word "throw" is no longer appropriate because returns are no longer thrown, and wasn't appropriate before either because it made no sense unless you knew how returns were implemented in R2 internally. So we need a suggestion for what to call this option before we can fix this.
As we debate questions like "Plan Minus Four" and other issues...
...going to agree with @Ladislav and others saying that not being able to write effective loop wrappers is blocking. This problem is a fundamental challenge to the basic premises of the language.
Looking for BREAK and CONTINUE is something that functions that wish to consider themselves looping constructs must actively do. Yet we can see that the bias of RETURN must be the opposite...a function should catch it unless told not to. It must be possible to throw a return "past" a function sometimes...BUT the same function might want to sometimes throw past, and sometimes not.
Because we don't have a canon example (that I know of) to really capture it, I'll propose one. Imagine UNLESS did not exist, and someone decided to implement it (they shouldn't need a C compiler to do so). For the sake of discussion let's say they write it like this:
unless: function [condition false-branch] [
if condition [return none]
forever compose [
set/any 'result (to-paren false-branch)
(Let's put aside the idea that it is a "crazy" implementation for this particular task. It is simple enough to understand, and applies to cases that are not "crazy"...so it's a good case to study.)
We see a clear problem in the expectations and handling of `foreach x [1 2 3] [unless x < 2 [break]]` and `foreach x [1 2 3] [unless x < 2 [return]]`. Both the BREAK and the RETURN living in FALSE-BRANCH want to escape their contexts and have the meaning based on where the source was passed in. Yet the BREAK and the RETURN in the body of UNLESS do *not* want to escape.
If we start here we can discuss whose responsibility it is to express what, and what the language limits are to having one's cake and eating it too are here. I don't have a complete solution in mind yet, just some thoughts, and wanted to see if I could elicit what existing thought would propose to the author who wished to use roughly such an implementation would be.
There's an extensive write-up (examples included) that distils down even more extensive discussions of this issue over the years:
In my perception, we have reached something looking like consensus over using one of the last two options (that is: "Definitional return only, with an option to not redefine RETURN and EXIT" or "Definitional return, with an option to not redefine RETURN and EXIT, dynamic return as a fallback") has emerged. One of the main remaining problems is how to name the function attribute to disable redefinition of RETURN and EXIT.
As an aside: for the purpose of _this_ ticket, BREAK and CONTINUE are non-issues. Simply because you can be careful about how you use loops in your wrapper, but you _can't_ do much about using a FUNCTION! for writing a wrapper function. That said, making dealing with BREAK and CONTINUE easier is certainly something that could be discussed. But under a separate ticket, please.
Based on some recent attempts of explaining the issue and the proposed fixes, I propose a new name for a "disabling" attribute (for solutions which need it):
Other suggestions for the attribute name from above wiki article:
- throw (R2 legacy)
And another suggestion which @HostileFork and I came up with on SO chat:
|14-Sep-2015 10:27||abolka||Comment : 0004641||Modified||-|
|10-May-2015 08:52||abolka||Comment : 0004641||Modified||-|
|10-May-2015 08:52||abolka||Comment : 0004633||Modified||-|
|10-May-2015 08:52||abolka||Comment : 0004641||Added||-|
|2-Apr-2015 01:10||abolka||Comment : 0004633||Added||-|
|2-Apr-2015 01:02||abolka||Comment : 0004632||Modified||-|
|2-Apr-2015 01:01||abolka||Comment : 0004632||Added||-|
|1-Apr-2015 17:53||fork||Comment : 0004631||Added||-|
|23-Mar-2013 17:11||BrianH||Comment : 0003727||Modified||-|
|23-Mar-2013 17:08||BrianH||Comment : 0003727||Added||-|
|23-Mar-2013 16:45||Ladislav||Comment : 0003726||Added||-|
|3-Nov-2010 07:46||abolka||Comment : 0002747||Removed||-|
|3-Nov-2010 06:46||Ladislav||Comment : 0002769||Added||-|
|3-Nov-2010 06:43||Ladislav||Comment : 0002768||Removed||-|
|3-Nov-2010 06:42||Ladislav||Comment : 0002768||Added||-|
|2-Nov-2010 22:36||BrianH||Comment : 0002766||Modified||-|
|2-Nov-2010 22:34||BrianH||Comment : 0002766||Added||-|
|2-Nov-2010 22:01||BrianH||Category||Modified||=> Unspecified|
|2-Nov-2010 22:01||BrianH||Summary||Modified||No [throw] attribute: USE captures RETURN and EXIT => No [throw] attribute: Mezzanine control functions capture RETURN and EXIT|
|2-Nov-2010 03:27||abolka||Comment : 0002747||Added||-|
|3-Jun-2009 17:13||BrianH||Comment : 0000898||Modified||-|
|3-Jun-2009 17:13||BrianH||Comment : 0000898||Modified||-|
|3-Jun-2009 17:12||BrianH||Comment : 0000898||Added||-|
|3-Jun-2009 17:09||BrianH||Summary||Modified||USE captures RETURN and EXIT => No [throw] attribute: USE captures RETURN and EXIT|
|3-Jun-2009 17:08||BrianH||Severity||Modified||major => block|
|20-Jan-2009 04:34||BrianH||Comment : 0000340||Added||-|
|20-Jan-2009 04:30||BrianH||Status||Modified||submitted => waiting|