Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make APPLY :DO [function ...] work like DO function ... #1950

Closed
Siskin-Bot opened this issue Feb 15, 2020 · 0 comments
Closed

Make APPLY :DO [function ...] work like DO function ... #1950

Siskin-Bot opened this issue Feb 15, 2020 · 0 comments

Comments

@Siskin-Bot
Copy link
Collaborator

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.

(This was originally requested by Ladislav on Github.)
; Current behavior
>> apply :do [:add 1 1]
** Script error: action! is missing its value1 argument

; Preferred behavior
>> apply :do [:add 1 1]
== 2

Imported from: CureCode [ Version: r3 master Type: Wish Platform: All Category: Native Reproduce: Always Fixed-in:none ]
Imported from: metaeducation#1950

Comments:

Rebolbot commented on Feb 15, 2013:

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:

    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:

>> do/args get probe 'add probe 1 probe 2 probe 3
add
1
2
3
== 5

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 :add 1 1
would need to be translated to this APPLY call:
    apply :do [:add none none none none 1 1]

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.


Rebolbot mentioned this issue on Mar 22, 2018:
RETURN/redo can break APPLY security


Rebolbot added the Type.wish on Jan 12, 2016


Oldes pushed a commit to Oldes/Rebol3 that referenced this issue Apr 1, 2020
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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants