Embed aggregate compose clarification

Hi Gophers,

I’m a bit confused today after reviewing a few design pattern implemented in Go and trying to translate this in a classic UML Class Diagram.

My understanding of the language is there’s no inheritance but embedding. An embedding struct/interface can use the methods and fields of another “base” struct/interface.

Some guys are talking about embedding as aggregation. So I’ve made some research and it reminds me of the confusion between aggregation and composition that I encountered a long time ago in Java.
From my standpoint, the more pragmatic answer to make the difference is that with composition, if no more references to a particular instance of A exist, its instance of B is destroyed which is not the case for aggregation.

Embedding is done by referencing the struct type without assigning a name for the field. Internally, it’s the name of the type of the struct that is used like below

type Car struct {
    Engine
}

If I add a field name then it’s no more embedding.

So, from my standpoint, it’s either composition or aggregation.
If the Engine struct is used by copy then it’s composition cause the instance will be destroyed once the Car instance will be destroyed.
If the Engine struct is a pointer, then it depends on whether the Engine type is used elsewhere or not.

Am I right or am I missing something?

type Car struct {
    e Engine
}
type Car struct {
    e *Engine
}

Thank you in advance for your help.

Your understanding of aggregation and composition seems correct to me.

1 Like

Since Go is a pass-by-value language, you need to pass pointers of objects to functions to be able to modify the object in the function. So, I have found myself using pointers to objects more frequently than objects themselves.

Purists would say to pass the objects themselves via a channel, and there is reason to do that also, especially if you intend to program to support concurrency.

But, if I am not programming for concurrency, I just use pointers to objects.

Hi Jeff,

Thanks for your feedback on this. I would just add that slice and maps as well as channels are “passed-by-pointer” (or “passed-by-reference” but are not created the classic way like in C++).

I figure out that I forgot the main question :upside_down_face:
So, from now, for named field it is clear but what about embedding? is-it considered as Aggregation or Composition ?

Thank you

@BigBoulard it could be either; In Go, this relationship is not communicated via syntax. Embedding a struct value instead of a pointer to a struct almost certainly implies composition. Embedding a pointer could mean association, composition or aggregation. Go uses documentation and clean code to communicate the relationships between struct fields.

type SinglyLinkedListNode struct {
    Value interface{}
    Next *SinglyLinkedListNode
}

type File struct {
    *Dir
    Name string
}

Personally, I feel that both of these structs fairly clearly communicate their relationships to SinglyLinkedListNode and Dir, respectively. In my hypothetical package, I could refactor File to something more like this:

package paths

type elem struct {
    // Dir that owns this file system element.
    // All elements are contained in a directory except for the root Dir.
    *Dir

    // Name of this file system element.
    Name string
}

// File on the filesystem.
type File struct {
    elem
}

// Dir is a directory in the file system that contains files and other directories.
type Dir struct {
    elem
}

Here we used idiomatic Go and comments to communicate to developers and users what relationships are associations, composition or aggregation.

Thanks @skillian. Makes more sense to me know.

Best.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.