cue-lang / docs-and-content

A place to discuss, plan, and track documentation on cuelang.org
5 stars 1 forks source link

tutorial: referring to embedded fields (a Go programmer's guide) #60

Open myitcv opened 4 months ago

myitcv commented 4 months ago

In https://github.com/cue-lang/cue/issues/2837, @r0b3r7137 raised an interesting question about why a reference to embedded field was giving an error.

Slightly tweaking the example:

import "list"

Network1: [...string] & ["1.2.3.4", "2.3.4.5"]
Network2: [...string] & ["3.4.5.6", "1.1.1.1"]

#Network: {
        ip: string
}

#NetworkX: {
        #Network
        allowed_ip: list.Contains(Network1, ip) & true
}

MyNetwork: #NetworkX & {
        ip: "1.2.3.4"
}

(note that allowed_ip is not hidden, so as to avoid triggering the bug mentioned in https://github.com/cue-lang/cue/issues/2839).

Given the code above, it was @r0b3r7137's intuition (quite possibly given experience from Go) that referring to ip in the call to list.Contains() would be fine, because #Network is embedded in #NetworkX.

This is not the case in CUE, because ip is not in scope at the point.

A natural solution therefore would be to change the reference to #Network.ip or #NetworkX.ip; neither of these are correct however, because they refer to the definition value, which will likely never be concrete. Instead the solution is to either use an alias:

import "list"

Network1: [...string] & ["1.2.3.4", "2.3.4.5"]
Network2: [...string] & ["3.4.5.6", "1.1.1.1"]

#Network: {
        ip: string
}

#NetworkX: N={
        #Network
        allowed_ip: list.Contains(Network1, N.ip) & true
}

MyNetwork: #NetworkX & {
        ip: "1.2.3.4"
}

or bring ip into scope:

import "list"

Network1: [...string] & ["1.2.3.4", "2.3.4.5"]
Network2: [...string] & ["3.4.5.6", "1.1.1.1"]

#Network: {
        ip: string
}

#NetworkX: {
        #Network
        ip: _
        allowed_ip: list.Contains(Network1, ip) & true
}

MyNetwork: #NetworkX & {
        ip: "1.2.3.4"
}

Either way, this seems to be the basis for a good tutorial where a Go programmer expects to hold embedding a certain way.

@r0b3r7137 - please do capture any further information that might help make this tutorial more useful.

cc @mvdan

mvdan commented 4 months ago

For some more context, https://alpha.cuelang.org/docs/concept/alias-and-reference-scopes/ already covers why one likely wants to use an alias in a situation like this, but I think this new tutorial could cover another "gotcha" for those of us coming from Go. And that is that embedding a struct type "promotes" its fields, which isn't happening in CUE. And even if the fields were promoted, referencing them is likely not what one wants, because of what the existing tutorial explains.

r0b3r7137 commented 4 months ago

Thanks to both of you, for being so responsive on the issue. Looking forward to adopt to cue and make some interesting things with it. I love the first approach, as @mvdan also mentioned in his example earlier, the second one about redeclaring field to bring the fields into scope feels a bit odd, but that's what I came up with as well intuitively 😄