When to use Type Embedding?

For now it occurs to me in DTOs sometimes the need to embed types (another DTO) like the traits.

If you’re familiar with other languages that support inheritance (Java, Python, C++, C#, etc.). For example, I have a simple TempFile implementation in some of my packages that is essentially this:

type TempFile struct {
    *os.File
}

func (f TempFile) Close() error {
    if err := f.try("close", func(f TempFile) error {
        return f.File.Close()
    }); err != nil {
        return err
    }
    return f.try("remove", func(f TempFile) error {
        return os.Remove(f.File.Name())
    })
}

func (f TempFile) try(fn func(TempFile) error) error {
    if err := fn(f); err != nil {
        return fmt.Errorf(
            "error attempting to %s file %v: %w",
            what, f.Name(), err,
        )
    }
    return nil
}

So essentially, my TempFile type works the same as an *os.File, except when Close is called, it calls the “base” *os.File’s Close function and then removes the file. If *os.File ever gets a new method, my TempFile will “inherit” it.

However, this is the only situation that I can think of where I’ve done this. Usually I end up forgetting about embedded functions and I accidentally do something like this:

func (f TempFile) Read(p []byte) (n int, err error) {
    // ...
    nn, err := self.Read(p)    // oops, I meant self.File.Read...
    // ...
}

Which is pretty obvious and yet I manage to make the same mistake more than once. I guess I’m just not cut out for inheritance-like embedding :upside_down_face:

1 Like

That reminded me of a line from Bitfield blog, in this article https://bitfieldconsulting.com/golang/commandments:

Don’t embed struct types so that they magically acquire invisible methods.

I think that’s what he’s referring to then. So it would very rarely be advisable to embed types, unless it is to build flat structs (without methods).

1 Like

Yea, that’s a really good point. I’ve done that especially with structs with common fields that I (un)marshal JSON to/from.

1 Like