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

Too early evaluation? #955

Closed
cueckoo opened this issue Jul 3, 2021 · 2 comments
Closed

Too early evaluation? #955

cueckoo opened this issue Jul 3, 2021 · 2 comments

Comments

@cueckoo
Copy link
Collaborator

cueckoo commented Jul 3, 2021

Originally opened by @kumorid in cuelang/cue#955

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

$ cue version
cue version 0.4.0-beta.1 darwin/amd64

Does this issue reproduce with the latest release?

Yes

What did you do?

I am trying to circumvent the problem reported in issue 951 by avoiding dijunctions of structs, opting for optional fields, but requiring exactly one of them to be provided.

The code I come up with is shown in file test.cue below.

However, when executing cue export test.cue I get the error reported below.

-- test.cue --
#T: {
  a?: int
  b?: int

  _A: a != _|_ 
  _B: b != _|_ 

  _valid: ((!_A && _B) || (_A && !_B)) & true
}

d: #T & {a: 56}

What did you expect to see?

{
  "d": {
     "a": 56
  }
}

What did you see instead?

#T._valid: conflicting values true and false:
    ./test.cue:8:12
    ./test.cue:8:42

It looks like field _valid is evaluated very early, resulting in bottom, provoking the error message.

However, if instead of the above code I use the following (removed unification with true in _valid):

-- test.cue --
#T: {
  a?: int
  b?: int

  _A: a != _|_ 
  _B: b != _|_ 

  _valid: ((!_A && _B) || (_A && !_B))

}

d: #T & {a: 56, _valid: _, _valid2: _valid & true}

Then I get the expected result above. I.e, _valid is not computed early...

@cueckoo
Copy link
Collaborator Author

cueckoo commented Jul 3, 2021

Original reply by @mpvl in cuelang/cue#955 (comment)

In CUE, errors in definitions and hidden fields are also errors. In the definition, both a and b are not defined, so _valid correctly evaluates to an error, which then correctly fails evaluation.

To fix this, one could rewrite this as:

#T: { a: int } | {  b: int }

The builtins in proposal #943 give a bit more flexibility. In this case, one could write:

#T: {
  numconcrete(1, a, b)
  a?: int
  b?: int
}

This approach would also allow specifying that at most one should be specified or any other combination of numbers.

@cueckoo
Copy link
Collaborator Author

cueckoo commented Jul 3, 2021

Original reply by @kumorid in cuelang/cue#955 (comment)

Yes, the proposal in #943 is what is needed. Agreed, much more terse and clear...

However, I am not sure I completely understand your reasoning.

Let me use a simpler example.

-- test.cue --
#T: {
  a?: int

  isA: a != _|_ 

}

d: #T & {a: 56}
e: #T 

Running cue export test.cue we get this intuitive result

{
    "d": {
        "a": 56,
        "isa": true
    },
    "e": {
        "isa": false
    }
}

That is, as d provides a value for a, a is not bottom in d, and isa==true, as expected.
However, as e does not provide a value for a, a is bottom in e, and we get isa==false.

All very intuitive and expected!

However, if we instead of comparison operations perform unification operations, the rules seem to change!
When running cue export test.cue on

#T: {
  a?: int

  isA: a != _|_ 
  valid:  isA & true
}

d: #T & {a: 56}

I would expect that given that isa==true in d, valid would ALSO be equal to true! (it is true & true)
Instead I get the error message: #T.valid: conflicting values true and false.

Why does the evaluator jump the trigger so early in this case?
It clearly does not know if isA is true or false (in fact isA is bool).

I interpret this as an inconsistency when evaluating one operator (comparison) or the other (unification)

Further proof of what I consider as inconsistent (imho). Consider the following struct:

#T: {
  isa: bool

  valid: isa & true
}
d: #T & {a: 56}

now, when running cue export test.cue we get the expected

{
    "d": {
        "isa": true
        "valid": true
    }
}

To me the valid field is the same in both cases: the unification of isa (a bool) and true, which can be either bottom or true

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

1 participant