
Golang concepts from an OOP point of view - markkit
https://github.com/luciotato/golang-notes/blob/master/OOP.md
======
gabesullice
While I appreciate that this is a work in progress and meant for learning, i
just want to caution readers and those new to Go that this is a somewhat
dangerous way to approach Go.

Simply mapping familiar vocabulary from an traditional OO language into Go
implies that the differences are superficial and the underlying concepts are
largely the same. The truth is that a lot of the traditional vocabulary was
very intentionally left out of Go.

For example, mapping embedded stucts to "multiple inheritance" masks the fact
that Go is trying to guide you into understanding the power of composition
over inheritance. It's not that it's impossible to understand that, but by
carrying over the terminology, you burden yourself with some preconceptions.

Like I said, I know this is a work in progress, but I encourage you to perhaps
map the terms but then write a paragraph or two about how they're _different_,
not the same.

This was a really nice resource for me when I first came to Go:
[http://spf13.com/post/is-go-object-oriented/](http://spf13.com/post/is-go-
object-oriented/)

~~~
coldtea
> _Simply mapping familiar vocabulary from an traditional OO language into Go
> implies that the differences are superficial and the underlying concepts are
> largely the same. The truth is that a lot of the traditional vocabulary was
> very intentionally left out of Go._

I find that what has been "intentionally left out of Go" is not necessarily a
good choice.

I also don't get the obsession with "idiomatic" programming.

Idiomatic Java/J2EE circa 1998-2008 was total crap (the programming style, not
the language). Even its then adherents admit it. Same holds for many other
languages/times.

Programmers should be consistent with a style, and teams should work with an
agreed upon style. But some languages designers to impose their ideas upon all
users of a language is wrong.

~~~
logicchains
>Idiomatic Java/J2EE circa 1998-2008 was total crap (the programming style,
not the language)

I think part of the aim of Go was to make this style impossible, by e.g.
removing inheritance, which plays a key role in most crappy Java code.

~~~
Zach_the_Lizard
Go's lack of generics however (except for special blessed built ins that are
OK) forces some of those bad patterns however.

Want to write a linked list that works on all types? Hope you like reflection
or annoying code generation or copy and paste.

~~~
dilap
or casting, which is a selective bit of loss of type safety (& a speed hit),
but is what the std library linked list impl actually uses, and is what pre-
generics java & objc used forever.

it ain't great, but it ain't a disaster, either.

~~~
Zach_the_Lizard
It's 1990s coding in 2016. We have a better way, and even go implements it for
certain special types.

~~~
dilap
i'm not saying it's great, but it's the most practical thing in most cases in
go, & it was missing from your list.

whether or not go would be better with generics is still an open question imo.

------
chimeracoder
> This is a discovery process, I'm writing this document to help myself
> understanding golang and maybe help others.

First: I took a brief look through this, and I didn't see anything that jumped
out as wrong. It's a pretty comprehensive document, especially for someone who
says they're just starting out, so kudos to James for writing it!

That said, from my experience in teaching Go classes and workshops for
beginners, comparing embedding to inheritance is usually a bad idea. It's not
that there aren't similarities, but in my experience it prompts new Go
programmers to write unidiomatic Go code when they think of embedding in that
way. They end up embedded structs the way they'd use inheritance in object-
oriented languages, and since Go isn't really intended as an object-oriented
language, it makes for unidiomatic code.

The main use cases of inheritance in OOP are accomplished by interfaces in Go,
not struct embedding. But at the same time, the main benefits of embedding
come from embedding _interfaces_ \- embedding structs is almost an
afterthought in the language. In fact, I tend to advise people against
embedding structs altogether. There are a few cases where it's worthwhile to
embed structs, but the use case for embedding interfaces is much more
powerful.

My advice for Go beginners: use interfaces more than you think you need to,
and forget that struct embedding is even possible. This rule of thumb helps to
write more idiomatic Go code when you're just getting started, before you have
a feel for what that really means.

~~~
weberc2
Interesting. I'm moving away from interfaces and toward plain structs (not
consciously, but naturally). I tend to only use interfaces when I want
polymorphism, not modularity. This is probably a consequence of me moving away
from a mock-all-the-things approach to testing.

~~~
skybrian
I recently heard a rule of thumb: "accept interfaces, return structs".

I haven't put it into practice, but it seems like this should give callers
enough flexibility to pass in whatever they like.

~~~
zalmoxes
That really depends on what you're tying to do. Say you have a Datastore
interface, which has some methods like "Create", "Update", "Delete", and a
MySQL + an inmem implementation.

You can have `datastore.New() Datastore`, which returns one of the
implementations, or you can have `datastore.NewMySQLStore,
datastore.NewInMemStore()`. Now you need a different method for each
implementation.

Also be careful with returning concrete type, you can run into this issue:
[https://play.golang.org/p/WHAW1X6elS](https://play.golang.org/p/WHAW1X6elS)

~~~
patates
Wow, that seems like a big issue. Is this accepted as a bug and being worked
on or yet another feature?

~~~
weberc2
It's not a bug. Interfaces are reference types. In this case, the interface is
implemented by a pointer type. The interface can be thought of as a pointer to
a nil pointer, but the "interface pointer" itself is not nil.

This is a tricky concept until you learn that interfaces are reference types.

Here's a simplified version of the previous example that illustrates this
concept:
[https://play.golang.org/p/pODBgaHXq5](https://play.golang.org/p/pODBgaHXq5)

------
timtadh
If you like these notes you might also like my article on the subject:
[http://hackthology.com/object-oriented-inheritance-in-
go.htm...](http://hackthology.com/object-oriented-inheritance-in-go.html)

In general, using struct embedding to simulate sharing code and data is pretty
limited. I rarely use this feature in my own code. However, having structs
which automatically implement interfaces is awesome because you can "say what
you need." You can also compose the interfaces together by embedding them. For
example of that, checkout the Map type in my data-structures repository:
[https://godoc.org/github.com/timtadh/data-
structures/types#M...](https://godoc.org/github.com/timtadh/data-
structures/types#Map)

------
morecoffee
Struct embedding has been mostly unpleasant in my experience. When a type is
embedded, only the methods that are explicitly on the interface/struct
actually get propagated, rather than all of public methods. This means that
wrapper types break optimizations around type punning. For example:
[https://play.golang.org/p/vIo1HtAeb4](https://play.golang.org/p/vIo1HtAeb4)

This happens within the standard library in ways that hurt performance. The
'image' package allows people to register their own decoders but limits the
API to an io.Reader. It can be an optimization if you could cast the inputted
reader to another more efficient type (like a ReaderAt), but you can't because
the image package wraps the Reader in its own "peeking" type. There's no way
to tell the type was embedded, or what other actual methods might have worked.

------
gtrubetskoy
> "receiver implict this parameter"

The parameter is actually quite explicit (unlike some other languages).

It would probably help your write up to talk about the difference between
(using your example):

    
    
      func (r Rectangle) Area() float64 {
    

and

    
    
      func Area(r Rectangle) float64 {
    

As well as (this is a common rookie mistake):

    
    
      func (r Rectangle) SetWidth(w float64) {
        r.Width = w // does nothing
    

and

    
    
      func (r *Rectangle) SetWidth(w float64) {
        r.Width = w

~~~
SomeCallMeTim
You might want to point to point that (if?) the second example does work? (And
that the difference is the *)

------
lloeki
"Go is a great OO language" is quite a simple and interesting take on it.

[https://www.youtube.com/watch?v=HqZQBmNVhBw](https://www.youtube.com/watch?v=HqZQBmNVhBw)

------
lucio
Author here, any pull request fixing typos, spelling and grammar, is welcomed.

~~~
pjmlp
I would use the real name of the language, Go.

Other than that, nice article.

------
matteuan
I think it also highlights how a lot of programmers have learned everything
only from one point of view. Concepts like interfaces, structures and types
are general and abstract, they should not be explained in terms of OOP,
instead they should be used as tools to explain OOP.

------
dizzy3gg
thanks, this is helpful for quick understanding of go

------
Animats
Go has most of the machinery of objects, but not the encapsulation. There are
no private fields in structs.

~~~
barsonme
Well, yes kind of.

    
    
        type foo struct {
            a int // "private"
            B int // "public"
        }
    

You cannot specify default values and Go refers to them as "exported" not
private, but technically they are "private" in the sense that they can only be
accessed via methods.

~~~
kuschku
is a field named "ß" private or public? Or ĸ?

~~~
skj
Definitely one or the other, but the confusion means it's best practice to
avoid fancy letters for identifiers.

~~~
kuschku
Well, there's people writing code in other languages.

I know in Japan and Germany it's still kinda common for larger companies to
build codebases in local languages.

Which in turn can lead to these issues.

