Skip to content
This repository has been archived by the owner on Nov 18, 2021. It is now read-only.

Support a must() builtin #575

Closed
myitcv opened this issue Oct 28, 2020 · 8 comments
Closed

Support a must() builtin #575

myitcv opened this issue Oct 28, 2020 · 8 comments
Labels
builtin FeatureRequest New feature or request
Milestone

Comments

@myitcv
Copy link
Contributor

myitcv commented Oct 28, 2020

This has come up various times on Slack, noting here for posterity (and so it can be referenced)

The name must() was also thrown into the 馃毑 shed.

Is your feature request related to a problem? Please describe.

Sometimes it is necessary to declare arbitrary constraints on a field.

Taking one such example from Slack, where we try to define #Foo as a string that must contain a numeric value greater than 5:

#Foo: constrain(strconv.Atoi(#Foo) > 5)

Describe the solution you'd like

As above.

Describe alternatives you've considered

The current alternative is to declare additional (hidden) definitions that express the constraint:

#Foo: string
_#checkFoo: strconv.Atoi(#Foo) & >5

Contrast the proposed constrain() builtin which allows the constraint to be declared on the field itself, which is much clearer for the author, reader and user.

Additional context

n/a

@myitcv myitcv added the FeatureRequest New feature or request label Oct 28, 2020
@mpvl
Copy link
Contributor

mpvl commented Nov 27, 2020

I vote for must.

@jlongtine
Copy link
Contributor

jlongtine commented Nov 27, 2020 via email

@mpvl mpvl added this to the v0.3.1 milestone Jan 18, 2021
@mpvl mpvl added the builtin label Jan 18, 2021
@myitcv myitcv changed the title Support a constrain() builtin Support a must() builtin Jan 26, 2021
@extemporalgenome
Copy link
Contributor

extemporalgenome commented Jan 30, 2021

I have been thinking about this issue as well, particularly around how strings.MinRunes takes the value as an implicit parameter (which has benefits and drawbacks).

That said, I wonder if the self-referential #Foo is a design liability. Are there any cases in which the right-hand-side #Foo could be ambiguous?

Pretend that strings.Contains, strings.Count, etc, accepted only explicit parameters (so we could express "receiver is contained by" using the same function in which we currently only express "receiver contains").

// if #Foo isn't one of these fruit, it must be two or more words
#Foo: "apples" | "oranges" | "pears" | =~ #"(\w+)(\s+\w+)+"#
#Foo: constrain(strings.Count(#Foo, #Foo) < 7)

Pretend the author of the above intends the first strings.Count parameter to bind to the definition (i.e. bind to the receiver, though I'm not sure what terminology we use for that), while the second parameter is intended to mean "any value matching the definition #Foo"), thus as a whole the constraint would mean: any valid #Foo must contain fewer than 7 fruit (and fewer than 14 words, presumably, though that'd be out of scope for strings.Count to intelligently handle).

However, since #Foo binds to the receiver, this really means that any matching concrete string must contain fewer than 7 occurrences of itself, which is certainly true, but not very useful to express.

If we had a special symbol to refer to the receiver, we'd avoid this hypothetical issue, and potentially reduce reader confusion ("is this an unresolvable circular reference? I thought those were disallowed?").

Using the original example, perhaps we could have a notation for referring to the receiver, such as @ or $ (neither of which is presently a valid identifier):

#Foo: constrain(strconv.Atoi(@) > 5)

Perhaps this is also worth a special symbol, for example -> to mean "such that the following is true" ?

#Foo: -> strconv.Atoi(@) > 5

or an explicit form without a magic identifier:

#Foo: x -> strconv.Atoi(x) > 5

(where x is a local binding for the receiver)

@bttk
Copy link

bttk commented Mar 29, 2021

I was surprised to learn that this is not what alias was used for:

d=#Date: {
	=~#"^\d{4}-\d{2}-\d{2}$"#
	#valid: time.Parse(d, time.RFC3339Date) & true
}

cue eval -e '(#Date & "2021-01-32")' -c
"2021-01-32"

@myitcv
Copy link
Contributor Author

myitcv commented Mar 30, 2021

@bttk you can't use an alias in the following example:

package x

import "list"

x: [...int] & list.MinItems(3)
x: [1, 2, 3]

The use of implicit parameters is missing from the spec, which I've raised as #863

The intention of must is to, in most cases, remove the repetition that comes with aliases, and verbosity of embedded scalars.

@verdverm
Copy link
Contributor

@bttk There is an excellent write up on several related constructs (alias, let, hidden fields) here: #699 (comment)

@myitcv
Copy link
Contributor Author

myitcv commented Mar 30, 2021

Good memory, @verdverm 馃槃

@cueckoo
Copy link

cueckoo commented Jul 3, 2021

This issue has been migrated to cue-lang/cue#575.

For more details about CUE's migration to a new home, please see cue-lang/cue#1078.

@cueckoo cueckoo closed this as completed Jul 3, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
builtin FeatureRequest New feature or request
Projects
None yet
Development

No branches or pull requests

7 participants