You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
DO function generates a redo value, which then causes the outer DO evaluator to call the function as if it were specified inline, taking any arguments it needs. It basically fakes R2's DO function behavior, but with cleaner semantics.
It would be nice if APPLY would do something similar when calling DO, and pass the (possibly reduced) arguments to the function, minus the function argument itself. If the arguments are reduced because we're not using /only, the value block should only be reduced once, then the values saved for the next reference. That has a bit of overhead in this case, but is less overhead than calling APPLY twice. This should only be done in the DO function special case, which should be detectable ahead of time.
This is just a way to make APPLY :DO more consistent with DO for people who would expect them to be, a usability trick comparable to the DO function trick.
This is not really related to #1949, and that fix would still be needed for security reasons. That fix is about clearing the redo flag for redos that escape Apply_Block. This fix would make the normal redo case never escape in the first place.
(This was originally requested by Ladislav on Github.)
; Current behavior>> apply :do [:add11]
** Script error:action! is missing its value1 argument
; Preferred behavior>> apply :do [:add11]
==2
One problem with this is that technically the original call to DO is wrong in this case, because the 1 1 are passed as arguments to the /args and arg parameters, respectively. So maybe a better approach would be that while DO is the applicant function, and the first (reduced) element of the values block is another function, change the applicant to that first element and go forward in the value block.
This transformation would be equivalent to changing this:
apply :do [:any-func ...]
into this:
apply :any-func [...]
without calling DO at all.
This approach would have less overhead than caching a pre-reduced values block. It would be at the cost of having DO not consider or even take its /args ot /next options when passed a function value, but since those options don't apply to function values that is likely not much of a loss.
Rebolbot commented on Feb 15, 2013:
Submitted by:Ladislav
Yes, that idea looks acceptable, IMO. However, if we keep the RETURN/REDO in user space, we can have unlimited number of variadic functions and we may need to set up a general policy for APPLY, DO, etc.
Rebolbot commented on Feb 15, 2013:
Submitted by:BrianH
No etc., just APPLY - see #1949 for that, or this ticket for the combination of APPLY and DO. DO on its own already has a policy, and all other functions are covered by DO and/or APPLY. And it doesn't matter whether we remove RETURN's /redo option: the fact that these can be created easily in native code means that we need to set a policy anyways. R3 is open source, so even native code is user code.
That doesn't mean that we want to make RETURN/redo, or native code for that matter, available to sandboxed code. Fortunately it's easy to remove an option when sandboxing.
Rebolbot commented on Feb 19, 2013:
Submitted by:BrianH
OK, so further testing has determined that both of us were wrong about what DO function does. For example:
That proves that DO consumes its /args argument, and then afterwards calls the function from the position after the /args argument. So, in order to be semantically compatible, this code:
do :add11
would need to be translated to this APPLY call:
apply :do [:add none none none none 11]
That is not acceptable to have to write, not just because it looks awful, but also because it breaks the none-padding of APPLY for the DO function.
APPLY does none-padding so that we don't have to specify all the options of the function we are applying, just the options up to the ones we want to specify. Then, we put the most commonly specified options first, which makes APPLY calls shorter. It also lets us add options to a function without breaking all existing APPLY calls, so long as the option is added to the end (or at least after all options that are ever called, so usually before the /local option).
If we have any redo take its arguments from the same argument block as the function that returned it, then we would have to write out all of the missing nones, even for local variables specified with /local. And then we wouldn't be able to add any options to the function because existing calls to it would be fixed-length, and for RETURN/redo calls or other Rebol function redos you wouldn't even be able to add a local variable in subsequent versions. Even if we just limit it to DO, DO has two options that take one argument each, so that's four nones, and we'll never be able to add another option to DO again or else it will break your code. That's just unacceptable.
So, we can't have a special case for APPLY :DO because the resulting APPLY calls would be terrible on many levels. We have to dismiss this whole approach, and this ticket.
Rebolbot commented on Feb 19, 2013:
Submitted by:Ladislav
It is good it has been determined how argument passing is performed in R3.
This makes APPLY :DO consistent with DO, as a special case for DO only.
It should deal with what will be perceived as an R3 bug by many users.
See Oldes/Rebol-issues#1950 for the rationale behind this.
The transformation is equivalent to changing this:
apply :do [:any-func ...]
into this:
apply :any-func [...]
without calling DO at all.
Originally suggested by Ladislav: rebol#80
(cherry picked from commit cd8250e)
Submitted by: BrianH
DO function generates a redo value, which then causes the outer DO evaluator to call the function as if it were specified inline, taking any arguments it needs. It basically fakes R2's DO function behavior, but with cleaner semantics.
It would be nice if APPLY would do something similar when calling DO, and pass the (possibly reduced) arguments to the function, minus the function argument itself. If the arguments are reduced because we're not using /only, the value block should only be reduced once, then the values saved for the next reference. That has a bit of overhead in this case, but is less overhead than calling APPLY twice. This should only be done in the DO function special case, which should be detectable ahead of time.
This is just a way to make APPLY :DO more consistent with DO for people who would expect them to be, a usability trick comparable to the DO function trick.
This is not really related to #1949, and that fix would still be needed for security reasons. That fix is about clearing the redo flag for redos that escape Apply_Block. This fix would make the normal redo case never escape in the first place.
Imported from: CureCode [ Version: r3 master Type: Wish Platform: All Category: Native Reproduce: Always Fixed-in:none ]
Imported from: metaeducation#1950
Comments:
Submitted by: BrianH
One problem with this is that technically the original call to DO is wrong in this case, because the 1 1 are passed as arguments to the /args and arg parameters, respectively. So maybe a better approach would be that while DO is the applicant function, and the first (reduced) element of the values block is another function, change the applicant to that first element and go forward in the value block.
This transformation would be equivalent to changing this:
This approach would have less overhead than caching a pre-reduced values block. It would be at the cost of having DO not consider or even take its /args ot /next options when passed a function value, but since those options don't apply to function values that is likely not much of a loss.
Submitted by: Ladislav
Yes, that idea looks acceptable, IMO. However, if we keep the RETURN/REDO in user space, we can have unlimited number of variadic functions and we may need to set up a general policy for APPLY, DO, etc.
Submitted by: BrianH
No etc., just APPLY - see #1949 for that, or this ticket for the combination of APPLY and DO. DO on its own already has a policy, and all other functions are covered by DO and/or APPLY. And it doesn't matter whether we remove RETURN's /redo option: the fact that these can be created easily in native code means that we need to set a policy anyways. R3 is open source, so even native code is user code.
That doesn't mean that we want to make RETURN/redo, or native code for that matter, available to sandboxed code. Fortunately it's easy to remove an option when sandboxing.
Submitted by: BrianH
OK, so further testing has determined that both of us were wrong about what DO function does. For example:
That proves that DO consumes its /args argument, and then afterwards calls the function from the position after the /args argument. So, in order to be semantically compatible, this code:
That is not acceptable to have to write, not just because it looks awful, but also because it breaks the none-padding of APPLY for the DO function.
APPLY does none-padding so that we don't have to specify all the options of the function we are applying, just the options up to the ones we want to specify. Then, we put the most commonly specified options first, which makes APPLY calls shorter. It also lets us add options to a function without breaking all existing APPLY calls, so long as the option is added to the end (or at least after all options that are ever called, so usually before the /local option).
If we have any redo take its arguments from the same argument block as the function that returned it, then we would have to write out all of the missing nones, even for local variables specified with /local. And then we wouldn't be able to add any options to the function because existing calls to it would be fixed-length, and for RETURN/redo calls or other Rebol function redos you wouldn't even be able to add a local variable in subsequent versions. Even if we just limit it to DO, DO has two options that take one argument each, so that's four nones, and we'll never be able to add another option to DO again or else it will break your code. That's just unacceptable.
So, we can't have a special case for APPLY :DO because the resulting APPLY calls would be terrible on many levels. We have to dismiss this whole approach, and this ticket.
Submitted by: Ladislav
It is good it has been determined how argument passing is performed in R3.
The text was updated successfully, but these errors were encountered: