Remix.run Logo
noisy_boy 4 days ago

Am I the only one who found the described behavior to be intuitively correct? I did expect it to print "abc.com".

nine_k 4 days ago | parent | next [-]

This may be intuitively correct, but to my mind it is architecturally wrong. A good language should not tolerate ambiguity and offer to guess which behavior is correct.

wild_egg 4 days ago | parent | next [-]

It's not ambiguous though. The behaviour is very clearly defined in the language spec.

https://go.dev/ref/spec#Selectors

As far as language specs go, Go's is really quite concise and I strongly encourage everyone I onboard to spend an afternoon reading it end to end at some point in their first couple weeks.

tayo42 4 days ago | parent | prev [-]

Why is it ambiguous though? The second URL is nested

Are thy not accessed like

opts.URL == abc.com

and

opts.BarConnectionOptions.URL == xyz.com

what leads you think otherwise?

tsimionescu 4 days ago | parent [-]

If there were no duplicate URL field, say they were called FooURL and BarcoURL, you could access them as `opts.FooURL` and `opts.BarcoURL`. They are both fields of `opts`, via embedding. It's just that FooURL is embedded directly, while BarcoURL is coming from two levels of embedding.

nvlled 4 days ago | parent | prev | next [-]

I'm confused at the responses saying this intuitive. It's like saying:

  var x string
  x = "abc.com"
  x = "xyz.com"
  fmt.Println(x)
will print abc.com and that's totally expected.

The normal intuition would be that the latter operations or (re)definitions override the preceding ones.

graynk 4 days ago | parent [-]

It's not at all like saying that.

The order of operations has nothing to do with it.

  opts := Options{
    FooService: FooService{URL: "abc.com"},
    BarService: BarService{
      BarConnectionOptions: BarConnectionOptions{
        URL: "xyz.com",
      },
    },
  }
is equivalent to

  opts := Options{
    BarService: BarService{
      BarConnectionOptions: BarConnectionOptions{
        URL: "xyz.com",
      },
    },
    FooService: FooService{URL: "abc.com"},
  }
nvlled 4 days ago | parent [-]

I'm making an analogy using simple assignments to show more clearly that it's actually counter-intuitive, I'm not claiming what you seem to be refuting, which at best seems to be beside the point.

graynk 3 days ago | parent [-]

And the analogy is invalid, because it completely replaces the intuitive thing that's happening with an unintuitive thing that isn't happening. There are no "latter operations or (re)definitions" here.

nvlled 3 days ago | parent [-]

> There are no "latter operations or (re)definitions" here.

Yes, in the literal narrow sense, there is no such thing in the submitted article (if it isn't already clear, I'm referring to my own example). That's why it's an analogy. I don't know the precise term that go uses for this, closest is probably "shadowing", but again it doesn't matter, it is besides the point. The point is that the exhibited behaviour is unintuitive, in contrast to what the others are saying.

> it completely replaces the intuitive thing that's happening with an unintuitive thing that isn't happening

What is the intuitive thing are you referring to here? If it's my example, then you are in total agreement with me, but you seem to think otherwise. If you are referring to the linked article, then you are just merely invoking tautology, to disagree with me. It's intuitive because you said so, therefore my analogy is invalid. Did I get that right?

graynk 3 days ago | parent [-]

> Yes, in the literal narrow sense, there is no such thing in the submitted article

Therefore your analogy is invalid, because your example is doing something entirely different and throws away nested structs that the whole thing is about.

> The point is that the exhibited behaviour is unintuitive, in contrast to what the others are saying.

Why?

> Did I get that right?

No. Let's stick to the original example and add the order of operations from your example.

  type A struct {
    X string
  }

  type Nested struct {
    X string
  }

  type B struct {
    Nested
  }

  type Combined struct {
    A
    B
  }

  c := Combined{}
  c.X = "example.com"
  c.Nested.X = "something completely different"

  fmt.Println(c.X)
Do you still expect this to print "something completely different" or does this look intuitive now?

The unintuitive part is that this works in the first place and doesn't throw an error:

  type Combined struct {
    //A
    B
  }

  c := Combined{}

  //c.X = "example.com"
  c.Nested.X = "something completely different"
  fmt.Println(c.X)
But if you know about this unintuitive feature and are relying on it instead of accessing the fields by their fully qualified names, then you should already have a gnawing feeling that asks you "what happens when there are conflicts?" (and the answer is - it does the intuitive thing)
nvlled a day ago | parent [-]

> The unintuitive part is that this works in the first place and doesn't throw an error

What the hell? So you do agree that it's unintuitive but the supporting points you keep giving are completely, utterly tangential. That's what I have been saying all this time, that it's unintuitive, what you are even disagreeing with me for? The analogy?

I repeat this once again, I made the analogy to simplify and make it clear because some responses seems to miss it. I've already addressed your points, but you keep giving back the same supposed rebuttal, different words but same meaning. Nothing about what you say invalidates the analogy.

> But if you know about this unintuitive feature and are relying on it instead of accessing the fields by their fully qualified names, then you should already have a gnawing feeling that asks you "what happens when there are conflicts?" (and the answer is - it does the intuitive thing)

If you are deeply aware of the quirks, intuition no longer applies. You rely on intuition when you are in an unfamiliar situation. So again, nothing what you said just now supports any of your argument, whatever it is.

graynk 17 hours ago | parent [-]

> you do agree that it's unintuitive

You should really pay more attention to precision of wording and the meaning that it carries, because you keep mixing up different things into one big pile of hand-waving and equating things that are not equal :)

There is no single "it" here. There are two different behaviors here. One is intuitive. One is not. We were discussing the former one. The analogy was about the former one. And the analogy was imprecise and misleading, completely losing different levels of nesting which is the whole point - that's what makes this behavior (short-hand selection when names conflicts - NOT short-hand selection in general) intuitive.

> If you are deeply aware of the quirks, intuition no longer applies. You rely on intuition when you are in an unfamiliar situation

I agree! And what I'm saying is: if you rely on intuition and you don't know about the selector mechanism at all - you will explicitly write out this nested level to access the second-level nested variable (c.Nested.X) and side-step the issue altogether, and accessing the first-level nested variable (c.X) will get you first-level nested variable exactly as you would expect. That's the behavior. That's what we're discussing here. That's what the article is about. That's what everyone calls intuitive - it's not about the short-hand selection itself (which, as I said - is unintuitive, but will not shoot you in the foot, unless you really try).

I don't think I'm getting my point across though, so I suggest we wrap it up here.

creddit 4 days ago | parent | prev | next [-]

I don’t write Go at all but given the first example, also expected this.

I was very surprised that either example compiled, though.

b_e_n_t_o_n 4 days ago | parent | prev | next [-]

Yeah it makes sense to me as well.

adastra22 4 days ago | parent | prev [-]

What is the intuition for that?

binary132 4 days ago | parent [-]

I think it’s something like:

“The general rule is that I may access the direct embeds of my type anonymously.”

adastra22 4 days ago | parent [-]

Ok I don’t think anyone disagrees with that. But there are two embedded structs, both with a URL field.

noisy_boy 4 days ago | parent [-]

But the level of nesting isn't the same; only one of them has a direct URL field.

masfuerte 4 days ago | parent [-]

You would get the same result if both URL fields were nested one level deeper. Being directly nested isn't the point.