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

transmute in _in_place functions #1032

Closed
Licenser opened this issue May 19, 2021 · 0 comments · Fixed by #1217
Closed

transmute in _in_place functions #1032

Licenser opened this issue May 19, 2021 · 0 comments · Fixed by #1217
Assignees
Labels
enhancement New feature or request

Comments

@Licenser
Copy link
Member

Describe the problem you are trying to solve

patch_in_place and merge_in_place are low-level optimizations that take advantage of knowledge about the AST and compiler.

As they act the same we will only discuss the merge_in_place variant here but it can be said that the same logic and reasoning applies to patch_in_place

They handle a common case in tremor script:

let target = merge target of something_else end;

merge, by default treats its target (target in this case) as immutable, as in a merge operation does not change the target but only replaces it.

We achieve that by, when merge is called, cloning the target and then executing a mutating merge on this new clone.

That way merge is considered an immutable expression, nothing between merge and end changes the world around it or has side effects.

For the special case where the target, and the variable the return of the merge are the same we skip the cloning part and the assignment part but instead mutate the variable in place.

The question may arise "but what happens if the in place merge references the value that it replaces?" Which is fair. The behavior remains safe.

let target = merge target of merge target of something_else end end;

would be executed as (pseudocode):

let _target1 = merge target of something_else end;
let target = merge target of _target1 end;

The inline reasoning:

// This function is called when we encounter code that consumes a value
        // to patch it. So the following code:
        // ```tremor
        // let event = patch event of insert "key" => "value" end
        // ```
        // When executed on it's own would clone the event, add a key and
        // overwrite original event.
        //
        // We optimise this as:
        // ```
        // patch_in_place event of insert "key" => "value" end
        // ```
        //
        // This code is generated in impl Upable for ExprRaw where the following
        // checks are performed:
        //
        // 1) the patch is on the RHS of an assignment
        // 2) the path of the assigned value and the path of the patched
        //    expression are identical.
        //
        // In turn this guarantees (at compile time):
        //
        // 1) The target (`expr`) is a path lookup
        // 2) The target is not a known constant as otherwise the assignment
        //    will complan
        // 3) this leave the `expr` to be either a local, the event, the state,
        //    metadata or a subkey thereof.
        //
        // And the following guarantees at run time:
        //
        // 1) the `expr` is an existing key of the mentioned categories,
        //    otherwise `expr.target.run` will error.
        // 2) `value` will never be owned (however the resolve function is
        //    generic so it needs to return a Cow)

Describe the solution you'd like

Not urgent but it would be nice to get rid of this, it might disappear along with a rewrite to compilation or a virtual machine for tremor-script.

Notes

Followup to #1015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants