opa icon indicating copy to clipboard operation
opa copied to clipboard

Functions and variables are not equivalent with lookup on undefined value under negation

Open JamiesWhiteShirt opened this issue 6 months ago • 4 comments

Short description

I expect test_variable and test_function here to be equivalent:

v := { "foo": true }

variable := v if {
  false
}

function(_) := v if {
  false
}

test_variable if {
  not variable.foo
}

test_function if {
  not function("bar").foo
}

However, test_variable is true while test_function is not.

I suspect that the test_function case is equivalent to the following where it fails because the value of the function is undefined:

test_function_equivalent if {
  r := function("bar")
  not r.foo
}

I am not sure if this expected behavior or not. My thinking is that variable and function("bar") should be substitutable without changing the behavior, but it appears to not be the case.

If this is expected behavior, could you perhaps explain why that is?

Steps To Reproduce

Run the above snippet as a test.

Expected behavior

Additional context

JamiesWhiteShirt avatar May 09 '25 13:05 JamiesWhiteShirt

Hi there! And thanks for reaching out about this. It's a great question!

If you have the OPA VS Code extension with Regal installed, you can use the compiler explorer to understand what's happening here. Right click anywhere in an open file and click "Source Action..." and you'll see that option. At the last compiler stage that has an impact here, your policy looks something like this:

package p

v := {"foo": true}

variable := data.p.v if false

function(_) := data.p.v if false

test_variable if { 
    not data.p.variable.foo
}

test_function if {
    data.p.function("bar", __local1__) # same as __local1__ = data.p.function("bar")
    not __local1__.foo
}

So while test_variable will negate the whole data.p.variable.foo reference, test_function will first call the function to store the result of that, then negate the result of referencing .foo from that. Obviously, evaluation never makes it that far, as the result is undefined.

This is "expected" behavior in the sense that it follows the current rules of compilation/evaluation. But as you're alluding to, there's a discrepancy between that and what policy authors might reasonably expect would happen.

I believe looking into how cases like this could be improved is part of the "Design: and/or/not/alternative" item from the OPA roadmap.

anderseknert avatar May 11 '25 07:05 anderseknert

I see. Using the compiler explorer is a good tip to understand what is going on under the hood.

I guess for now it may be advisable for policy authors to avoid using negation on expressions that desugar into local variables. This applies to doing lookups on function values as demonstrated, and I suspect this also applies when a function value is passed directly as a parameter to another function, possibly more.

In these cases you can either make these variables explicit or you can move the expression into a function and negate its result.

Maybe this is something that should be addressed in Regal?

JamiesWhiteShirt avatar May 12 '25 07:05 JamiesWhiteShirt

Yeah, the most commonly raised gotcha is probably how not fails to negate undefined references passed as function arguments:

not func(arg) 

That'll still be undefined if arg is undefined, for the same reason previously mentioned.

I'd love to have Regal help out with this! But it's a tricky case IMHO as it's not entirely clear to me what we'd suggest as the alternative, better approach. Definitely open to ideas, here or in a new issue in the Regal tracker :)

anderseknert avatar May 12 '25 11:05 anderseknert

This issue has been automatically marked as inactive because it has not had any activity in the last 30 days. Although currently inactive, the issue could still be considered and actively worked on in the future. More details about the use-case this issue attempts to address, the value provided by completing it or possible solutions to resolve it would help to prioritize the issue.

stale[bot] avatar Jun 11 '25 21:06 stale[bot]