Current syntactic and semantic redundancies #699
-
CUE appears to have a few syntactic forms and concepts that may have had clearer distinctions in the past, but now are somewhat interchangeable. Equivalence of hidden identifiersThe following appear to all be equivalent in practice, even if there are subtleties or nuances in their particular semantics (examples borrowed from #687):
These common properties appear to apply to all three "byte" declarations:
Further, given CUE's proximity to and initial influence from the Go language, De-shadowingIn the tutorial lesson on aliases, we have: https://cuelang.org/docs/tutorials/tour/references/aliases/
This can also be accomplished equivalently with a hidden field:
Hidden fields vs hidden definitionsNormal definitions ( Normal (exposed) definitions are primarily distinguished from exposed fields in that definitions are not normally output in JSON or other data formats, but can generate schemas, such as in OpenAPI output: this is a meaningful, compelling design. However, since hidden definitions are not exported as schemas, the only distinction between hidden fields and hidden definitions appear to be their default behaviors regarding struct openness: definitions, including hidden definitions, are closed by default, but can use For non-struct constraints, there doesn't appear to be any functional distinction between hidden definitions and hidden fields. Therefore, aside from the slight syntactical convenience of using a nested hidden definition instead of a nested hidden field when a closed struct is desired, there does not appear to be much benefit to the existence of hidden definitions (we could remove Aliases for referring to non-identifiersThe spec demonstrates that non-let aliases can be used to reference fields that otherwise could not be referenced (https://cuelang.org/docs/references/spec/#aliases):
For a reader who doesn't know about this feature of the language, it's particularly difficult to interpret (I ended up asking about it in #687 because I couldn't figure out from the documentation alone what it actually meant). In this case it introduces a field called Anyways, this form of alias does not appear to introduce any capability that a hidden field couldn't accomplish equally well, since the following produces the same result:
or for that matter...
Since CUE is commutative, there is of course no difference (that I'm aware of) between introducing a concrete value in Implications of the aboveHidden definitions (
I have not spent much time thinking about the use of |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 2 replies
-
Thanks for the feedback. I'll try to explain the raison d'etre of the various constructs. I'll be curious to hear if that explains the differences sufficiently or if there is still an uneasy feeling of redundancy or suggestions for simplifications, beyond the ones confirmed below. AliasesUnlike fields, which always have a Aliases serve various functions that can otherwise not be accomplished. One important one is being able to refer to generated fields, such as:
or
The construct In general, it is good to not have arbitrary semantic restrictions on what seemingly is allowed by syntax. Most language proposals we have made or are planning to make are mostly just a generalization of which productions are allowed in which place. Granted, and as you remarked, CUE is currently a bit inconsistent in this regard. For instance,
and
should be allowed. Both variants solve some important issues that are currently unsolvable. But if nothing else, it would be consistent to allow it. The reason this doesn't exist yet is partly a function of it just hanging on the to-do list and partly waiting on phasing out past mistakes/usages: what is now Detailed semantics of aliasesEven if we did have value aliases, they would not be a substitute for field aliases. One semantic subtlety arises from the way graph unification works and for the duality that arises from viewing types and values as the same thing. Suppose we have value aliases and then consider
Using
Clearly, the correct one to use for defining a linked list type is We believe it is possible to come up with some good guidelines for users to figure out which to use when. The main reason value aliases don't exist yet is because its syntax conflicts with the old meaning of aliases and we need some transition. But also, one would need to consider to allow either Note that it is not possible to write Also note that in general, one cannot rewrite
as
or
The former would change the meaning of the original, especially when The latter introduces a new field ( It is also in general not possible to write
because
would yield As a general rule of thumb, one should always use aliases to work around unaccessible fields. Disallow aliases that don't add functionality?I know that above I claimed that it is good to not have arbitrary semantic restrictions on what seemingly is allowed by syntax. I know this contradicts what you are suggesting above. Admittedly this is a trade-off. I remember the discussion in this matter with type aliases in Go. There is something to say to disallow certain uses where people can really shoot themselves in the foot or even avoiding different ways to do the same thing. But this has to be weighed against the possible frustration users may face by doing so. For instance, consider a user is given a schema with fields of the form Another reason to not gratuitously block use cases is that a language construct often ends up being used for good uses that are unforeseen by its creator. Blocking constructs may impair this natural evolution. In this case, there doesn't seem to be a real harm in allowing it, except for being able to solve a few things in different ways, but that doesn't seem to weigh up to the potential frustration and other disadvantages. De-shadowingShadowing can be solved in several ways in CUE, as you noticed. CUE doesn't really have a construct that is just for de-shadowing. The current techniques for de-shadowing are all a consequence of constructs that were designed for another purpose: aliases were introduced initially to refer to computed and other fields that otherwise cannot be referenced. By not restricting their use they can be used for de-shadowing. But also, quoted fields cannot be referenced. This is a result of finding the simplest rule to explain the inability reference A third way to de-shadow would be the use of value references (don't exist yet, as explained above), which probably would introduce the most generic solution. I agree that there should be better documentation explaining recommended techniques for de-shadowing. Here again some of the design decisions were guided by the ability to do automatic rewrites. One technique for CUE-ifying other sources is to start with everything quotes fields, use references only for builtins and then let
|
Beta Was this translation helpful? Give feedback.
-
This discussion has been migrated to cue-lang/cue#699. For more details about CUE's migration to a new home, please see cue-lang/cue#1078. |
Beta Was this translation helpful? Give feedback.
Thanks for the feedback. I'll try to explain the raison d'etre of the various constructs. I'll be curious to hear if that explains the differences sufficiently or if there is still an uneasy feeling of redundancy or suggestions for simplifications, beyond the ones confirmed below.
Aliases
Unlike fields, which always have a
:
, an alias, never introduces something new and always just introduces a different name to refer to an existing element, whether it be a value or field. Moreover, the only other place where=
is used is inlet
. More onlet
below. But for now, basically, any use of=
never introduces something that influences unification.Another way to view it, for
X = Y
for any let or …