Embeded struct pointers and struct literals

366 views
Skip to first unread message

steven099

unread,
Dec 10, 2009, 2:05:22 AM12/10/09
to golang-nuts
(part 1)
In reading the spec, playing with the language, and looking at other
people's code, it seems that embedding struct pointers is a quite
common way to reuse code. The problem is that struct literals don't
reflect the abstracted structure of embedded types.

In an unkeyed struct literal, the contents reflect the structure of
struct, so it makes sense to have cascading struct literals for the
embedded structs. However, in the keyed struct literal, the contents
aren't reflecting the structure, so requiring structured cascading
struct literals is incongruous. It would seem that you should be able
to use as a key the same identifier you'd use as a selector. If its a
struct pointer, you'd have to initialize the pointer first (or maybe
not...).

(part 2: Now here it starts getting more hypothetical)
In a struct literal, it seems iffy whether you should need to
initialize an embedded struct pointer before initializing its fields.
The intent is clear, and you are intended to have access to those
fields as though they were part of the struct.

However, if the struct pointer is not exported, it might be intended
that you can't access its methods without first using a package
supplied initializer. This is hardly a worse than being able to
initialize and use a struct without using the package supplied
initializer, and both can be blocked by simply not exporting the type
of the outside struct, but it is a consideration.

_________________

Does this (part 1, and maybe part 2) make sense, or am I missing
something?

Russ Cox

unread,
Dec 10, 2009, 2:18:39 AM12/10/09
to steven099, golang-nuts
Could you please make your question concrete
by giving specific code examples? I'm having a
hard time understanding what you've written.

Thanks.
Russ

steven099

unread,
Dec 10, 2009, 3:56:10 PM12/10/09
to golang-nuts
Sorry.

I was pointing out that it would seem that if I can initialize an
object like this:

p := new(Point);
p.X = 1;
p.Y = 2;
p.Z = 3;

then I should be able to initialize it like this:

p := &Point{ X: 1, Y: 2, Z: 3};

but I can't if T is declared

type Point2D struct {
X int;
Y int;
}

type Point struct {
Point2D;
Z int;
}

The expected way is:
p := &Point{Point2D: Point2D{X: 1, Y: 2}, Z: 3};

I was saying that requiring it to be structured this way when
initializing like this:
p := &Point{Point2D{1, 2}, 3};

makes sense, because the whole basis of the unkeyed literal is
structural, but it seems inconsistent to have to structure the literal
when initializing using keys, since the keyed literal is inherently
non-structural, and that it would be more consistent to use the
selector for a field as its key, irrespective of whether it belongs to
the struct itself or to an embedded struct.

I was wondering whether this makes sense, or if I'm missing something.
(not "the key is not the selector", thats a truism by default and
means nothing)

The second part was more hypothetical and was talking about, if keys
were the selectors as considered above, what to do if the embedded
type is a pointer, as in, either require explicit initialization, or
allow implicit initialization. I was trying to come up with a negative
side effect of the implicit initialization (such as the pointer itself
not being exported), but couldn't come up with a strong one. This is,
however sort of an addendum to the first question and not really the
main point.

Russ Cox

unread,
Dec 10, 2009, 4:27:14 PM12/10/09
to steven099, golang-nuts
> p := new(Point);
> p.X = 1;
> p.Y = 2;
> p.Z = 3;
>
> then I should be able to initialize it like this:
>
> p := &Point{ X: 1, Y: 2, Z: 3};
>
> but I can't if T is declared
>
> type Point2D struct {
>  X int;
>  Y int;
> }
>
> type Point struct {
>  Point2D;
>  Z int;
> }
>
> The expected way is:
> p := &Point{Point2D: Point2D{X: 1, Y: 2}, Z: 3};

You've got a valid point, but it's worth noting that
you also cannot translate:

p := new(Point);
p.Point2D.X = 1;
p.Point2D.Y = 2;
p.Z = 3;

into

p := &Point{Point2D.X: 1, Point2D.Y: 2, Z: 3}

And if the embedded Point2D is a pointer instead
of a value, you can't translate

p := new(Point);
p.Point2D = new(Point2D);
p.X = 1;
p.Y = 2;
p.Z = 3;

p := &Point{Point2D: new(Point2D), X: 1, Y: 2, Z: 3}

I don't think you're proposing either of these, but
there has to be a line somewhere, and we drew
a very conservative one.

The context-sensitive initialization lists are one
of the most complex parts of analyzers for C,
so we're shying away from doing too much here.

Especially since Go doesn't use embedding for
data subtyping (i.e. you can't pass a *Point where
a *Point2D is expected), l think this situation is
less common than it would be in other languages.

Russ

Steven Blenkinsop

unread,
Dec 10, 2009, 5:39:11 PM12/10/09
to golang-nuts
Okay, thanks. So I guess I'm to assume that this behaviour is somehow
a lot more complex than it seems. Well, I'll leave that judgment to
the people who make compilers then :)

~Steven
Reply all
Reply to author
Forward
0 new messages