cue icon indicating copy to clipboard operation
cue copied to clipboard

eval: len() of list with errors results in non-error length?

Open myitcv opened this issue 9 months ago • 4 comments

What version of CUE are you using (cue version)?

$ cue version
cue version v0.13.0-0.dev.0.20250303124518-d73e69059114

go version go1.24.0
      -buildmode exe
       -compiler gc
  DefaultGODEBUG gotestjsonbuildtext=1,multipathtcp=0,randseednop=0,rsa1024min=0,tlsmlkem=0,x509rsacrt=0,x509usepolicies=0
     CGO_ENABLED 1
          GOARCH arm64
            GOOS linux
         GOARM64 v8.0
             vcs git
    vcs.revision d73e690591145f0b19256beb5f62fc87f959b282
        vcs.time 2025-03-03T12:45:18Z
    vcs.modified false
cue.lang.version v0.13.0

Does this issue reproduce with the latest release?

Yes

What did you do?

# preamble
env CUE_EXPERIMENT=evalv3=1
env CUE_DEBUG=openinline=0

# export the full configuration
! exec cue export .
cmp stderr stderr.golden

# just z
! exec cue export -e z .
cmp stderr stderr.golden

-- x.cue --
package x

x: [{a!: string}, {b!: string}]
z: len(x)

-- stderr.golden --
x.0.a: field is required but not present:
    ./x.cue:3:6
x.1.b: field is required but not present:
    ./x.cue:3:20

What did you expect to see?

Passing test.

What did you see instead?

# preamble (0.000s)
# export the full configuration (0.049s)
# just z (0.045s)
> ! exec cue export -e z .
[stdout]
2
FAIL: /tmp/testscript4173821415/repro.txtar/script.txtar:10: unexpected command success
error running repro.txtar in /tmp/testscript4173821415/repro.txtar

Even though the list x is in error with respect to cue export, we can ask for its length and cue export that value.

At least through one lens, it's reasonable to assume that the result of that len() call should be an error, if its argument is in error.

This builds on the discussion in https://github.com/cue-lang/cue/issues/3711#issuecomment-2634897512.

It seems like there are at least two options:

  • Require that the arguments to len() are "not in error" with respect to the mode of evaluation and manifestation (cue export in this case)
  • Add must() so that we would instead declare:
x: [{a!: string}, {b!: string}]
z: must(isvalid(x)) & len(x)

(for some spelling of must() and isvalid())

myitcv avatar Mar 03 '25 13:03 myitcv

This complaint arose originally in the "help" channel of the "CUE" Slack workspace.

It is good that cue vet catches such violations of the constraining schema, but I was hoping to be able to rely on cue export to do the same validation in addition to exporting just the projecting expression that I need out of the input data.

seh avatar Mar 03 '25 13:03 seh

Thanks @seh. The context here is really useful. Because it points to a tricky aspect when it comes to defining the semantics of len():

Should it always require its arguments to be valid? Unless that answer is "yes, always" then the caller of len() needs to also think about a constraint (via must() or similar) that ensures the arguments are valid.

The reason I hesitate on the answer is that in general we want CUE to be as lazy as possible, in order that we can export/similar parts of very large configurations.

cc @rogpeppe @cuematthew for thoughts on that topic.

myitcv avatar Mar 08 '25 11:03 myitcv

Should it always require its arguments to be valid? Unless that answer is "yes, always" then the caller of len() needs to also think about a constraint (via must() or similar) that ensures the arguments are valid.

Rather than relying on a function or operator within the language to change this preference, I'd prefer a command-line flag on cue export—and, by implication, some sort of runtime configuration set on the evaluator—that would toggle between "ensure the universe as presented is valid per unification" and "narrow the scope of interest to just this expression, and ignore the rest".

seh avatar Mar 10 '25 02:03 seh

Still happens as of v0.15.0.

mvdan avatar Nov 14 '25 09:11 mvdan