Hacker News new | ask | show | jobs
by reedjosh 1516 days ago
Took me a second to see the difference in what you were doing between what I was doing.

In your case you're making a Kia car by making a regular car with a Kia motor.

In my case (at work) I'm making a type KiaCar struct { Car ... }.

Which is why I have to link a concrete type in the KiaCar to the Car if I want methods with Car receivers and KiaCar receivers to use the same concrete Motor.

I do like what you've written above though. I'll consider if I can use that instead of what I'm doing currently.

I'm just not entirely sure how I'd write methods for the KiaCar that knows what its concrete type is.

1 comments

Yeah, I think very, very few problems (if any) are better-suited to being modeled with inheritance rather than composition. Go sort of forces you to think about composition, and once you get the hang of it I'd bet you won't go back. When you need reuse, reach for composition. When you need polymorphism, reach for interfaces/callbacks. When you need both (for example, a BookStore that works with both Postgres and SQLite backends) then you reach for both:

    type BookStoreBackend interface {
        GetBook(isbn string) (*Book, error)
        PutBook(*Book) error
        ListBooks() ([]*Book, error)
        DeleteBook(isbn string) error
    }

    // BookStore embeds (i.e., is composed of) a Backend, which is an
    // interface type.
    type BookStore struct {
        // ... other fields

        // Backend supports PostgresBookStoreBackend, SQLiteBookStoreBackend,
        // FileSystemBookStoreBackend, MemoryBookStoreBackend (for testing),
        // etc.
        Backend BookStoreBackend
    }