Image for post
Image for post

Is Go an Object Oriented language?

Lukas Lukac
Sep 7, 2018 · 11 min read

The first technical article is dedicated to a slightly opinionated topic but an important one. Soon after you write your first Go program, you will start thinking about how to organise your code. Should I write a Function? Should I create a new Struct?

Eventually it all comes to the same question.

The answer is, like to everything in life: “it depends”.

Today’s article is presented by GophersLand citizen: Lukas [twitter].

About Author

I was doing PHP/Java for 7 years by now. I developed a bidding applications handling 100s of millions of bids from advertisers such as or Expedia. I created a poker social network TiltBook and even published a Udemy course on “Object Oriented Programming”!

About OOP

Before we are able to decide if Go is OO or not, we must first define an OO language.

When I started writing this article, I defined OOP based on the Wikipedia definition:

  • is a programming paradigm based on the concept of “objects”, which may contain data, in the form of fields, often known as and code, in the form of procedures, often known as
  • an Object’s procedures can access and often modify the attributes of the object with which they are associated
  • an Object’s internal state is protected from outside world (encapsulated) leveraging private/protected/public visibility of attributes and methods
  • an Object is frequently defined in OO languages as an instance of a Class

The above concept properties are implemented in most popular OO languages, Java and C++ by mechanics such as:

  • Encapsulation (possible on package level in Go)
  • Composition (possible through embedding in Go)
  • Polymorphism (possible through Interface satisfaction in Go. Type satisfies Interface without manually implementing it if it defines all the Interface methods. Since almost anything can have methods attached, even primitive types such as Int, almost anything can satisfy an interface)
  • Inheritance (Go does not provide the typical, type-driven notion of subclassing because it’s fragile and considered a bad practice, inferior to Composition)

OOP Original Conception

After I published the article, I realised the concept of Objects from historical perspective is extremely complex and subjective.

What surprised me the most is the fact, the creator of the term “object oriented”, Dr Alan Kay didn’t based the methodology on previously mentioned mechanics (Encapsulation, Composition, Polymorphism and Inheritance), those evolved further as side effects.

Alan Kay’s original conception was based on the following properties (thx Michael Kohl for providing this resource):

  1. Messaging (possible via Channels in Go)
    In terms of communication between Objects, how modules, objects communicate should be designed rather than what their internal properties and behaviors should be
  2. Local retention, protection, and hiding of state-process (possible by defining public/private attributes and methods in Go)
  3. Extreme late-binding of all things (possible via higher-order-functions and Interfaces in Go)
    A higher order function is a function that takes a function as an argument, or returns a function.
- I thought of objects being like biological cells and/or individual 

computers on a network, only able to communicate with messages (so

messaging came at the very beginning -- it took a while to see how
to do messaging in a programming language efficiently enough to be


- I wanted to get rid of data. The B5000 almost did this via its

almost unbelievable HW architecture. I realized that the

cell/whole-computer metaphor would get rid of data, and that "<-"

would be just another message token (it took me quite a while to

think this out because I really thought of all these symbols as
names for functions and procedures.

- My math background made me realize that each object could have

several algebras associated with it, and there could be families of

these, and that these would be very very useful. The term

"polymorphism" was imposed much later (I think by Peter Wegner) and

it isn't quite valid, since it really comes from the nomenclature of

functions, and I wanted quite a bit more than functions. I made up a

term "genericity" for dealing with generic behaviors in a

quasi-algebraic form.

Additional deep sources on OOP:

Local retention, protection, and hiding of state-process

In other words, Encapsulation

Encapsulation is all about maintaining your objects in a valid state and data hiding. Majority of OOP codebases are monoliths. Well, at least until 2017 before the whole Microservices boom…

Why replacing set of problems for less researched ones?

Monoliths apps have usually one big state, shared memory and state access is controlled using famous private/protected/public attributes/methods.

You know what? That works very well for a wide range of applications if you follow DDD and achieve a proper encapsulation!

How is encapsulation and shared memory achieved in object oriented languages?

public class FirstGopherlandCodeSnippet {
private boolean excitementLvl = 99;

What makes GoLang special?

The rise of multicore CPUs argued that a language should provide first-class support for some sort of concurrency or parallelism. And to make resource management tractable in a large concurrent program, garbage collection, or at least some sort of safe automatic memory management was required.

All this is very hard to achieve in current Object Oriented languages such as Java. Go took a different approach.

The number 1 feature of GoLang is the exact opposite definition of what OOP stands for. The alone definition, should be a sufficient first hint, suggesting a different implementation/way of thinking must be adapted.

This efficient communication is achieved especially using:

What about encapsulation? How is encapsulation achieved in GoLang?


package tar// Private, available only from within the tar package
type header struct {
// Public, available from other packages
func Export() {
// Private, available only from within the tar package
func doExport(h header) {

I like to think about it in this way:

Image for post
Image for post
ArchiveManager, TarManager, ZipManager…

Therefore, when designing your package specific scope encapsulation, start by designing a public API by defyining the minimum set of FUNCTIONS that shall be exposed to the outsite world.

An usage example of a standard library RSA pkg with clear input/output API:

package rsafunc EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) ([]byte, error) {
return []byte("secret text"), nil
cipherText, err := rsa.EncryptPKCS1v15(rand, pub, keyBlock)

There is no need to jump into creating a Struct straight away just because we are used to create Classes such as RsaEncryptionManager/RsaHandler for everything all the time from previous, differently designed languages.

Struct vs Object

The responsibility of an Object is to:

  • hide data from outsite world
  • define behaviour
  • perform messaging
  • maintain a valid state

The responsibility of a Struct is to:

  • maintain a valid state if implemented via pointers
  • group together multiple fields, even of a different type

Ability to directlyattach methods should be done to specific, small Structs, before things get messy. Just because there isn’t yet a term “GodStruct” (well, now there is), it doesn’t mean a Struct is excused to look like this monstrosity:

… I still love you Ethereum but good luck unit testing that thing…

I think the biggest “illusion” why Go looks like an Object Oriented language is due to the fact a Struct and an Object look so freaking simillar therefore is natural for developers coming from OO languages to write Go in such a manner. Except. They are not.

How does a Struct look like?

type MyFakeClass struct {
attribute1 string

Can such a Class (Struct) also have methods? Sure.

func (mc MyFakeClass) printMyAttribute() {

Perfect. Except… We have been both fooled like Instagram fanboys/fangirls by filters and convenient angles of that girl/guy from next doors…

The above method with a receiver argument (the Go term), can be also written as a regular function.

func printMyAttribute(mc MyFakeClass) {

Thank you Mihalis Tsoukalos, author of a book Mastering Go for this epiphany!

Struct vs Object behaviour

The difference is noticable from the following example.

Click to run the snippet:

We could achieve the desired “Object Oriented” behaviour by implementing a common pointer receiver function.

Click to run the snippet:

While this is a common pattern (technically, the only possible way to update a Struct without creating a new instance) and a recommended way of updating a Struct, I believe pointers should be used with a caution. But then, I am a huge fun of immutability so I may be slightly bias.

In the next section I am going to share my experience and some researched points when to use a Value Receiver and when a Pointer Receiver.

Value vs Pointer Receiver

When to use a Value Receiver:

  • if the receiver is a map, func or chan
  • if the receiver is a slice and the method doesn’t reslice or reallocate the slice
  • if the receiver doesn’t mutate its state
  • if the receiver is a small/medium array or struct that is naturally a value type (for instance, something like the time.Time type, XY coordinates, basically anything representing collection of fields), a ValueObject one could say

Advantages of a Value Receiver:

  • concurrently safe, compatible with GoRoutines (that’s why I use Go in first place)
  • Value Copy Cost associated with Value Receivers is not a performance bottleneck issue in absolute majority of applications
  • can actually reduce the amount of garbage that can be generated; if a value is passed to a value method, an on-stack copy can be used instead of allocating on the heap. The stack is faster because the access pattern makes it trivial to allocate and deallocate memory from it (a pointer/integer is simply incremented or decremented), while the heap has much more complex bookkeeping involved in an allocation or free
  • it directly, conciously forces to design small Structs
  • easier to argue about encapsulation, responsibilities
  • keep it simple stupid. Yes, pointers can be tricky because you never know the next project’s dev and Go surely is a young language
  • obvious I/O
  • unit testing is like walking through pink garden (slovak only expression?), means easy
  • no NIL if conditions (a NIL can be passed to a pointer receiver and cause a panic attack)

Advantages of a Pointer Receiver:

  • more efficient once allocated in terms of CPU and Memory (are those few ms actually a business requirement?)
  • can maintain and mutate state

When to use a Pointer Receiver:

  • working with large datasets, Pointer Receiver is more efficient
  • if the developer writes high performance analytical application like NewRelic or a new Blockchain DataStore DB
  • if the receiver is a Struct that contains a sync.Mutex or similar synchronizing field, the receiver must be a pointer to avoid copying (Why mutex in first place? Use channels)
  • if the receiver performs mutation (can be mostly avoided by designing pure functions with clear intention and obvious I/O)
  • if a Struct is maintaining state, e.g. TokenCache
type TokenCache struct {
cache map[string]map[string]bool
func (c *TokenCache) Add(contract string, token string, authorized bool) {
tokens := c.cache[contract]
if tokens == nil {
tokens = make(map[string]bool)
tokens[token] = authorized
c.cache[contract] = tokens

My personal rules when designing a Struct to maintain its state:

  • I make sure ALL attributes are PRIVATE, interaction is possible only via defined method receivers
  • I don’t pass this Struct to any goroutine

General rule for both types

If your Struct has a Value Receiver method, all other methods of this Struct should be Value Receivers.

The same for pointers.

If your Struct has a Pointer Receiver method, all other methods of this Struct should be Pointer Receivers.

Consistency FTW!

Personal ultimate 2 rules:

  • Write as many First Class Functions as possible and KISS.

func roll(s score) (score, bool) {
outcome := rand.Intn(6) + 1 // A random int in [1, 6]
if outcome == 1 {
return score{s.opponent, s.player, 0}, true
return score{s.player, s.opponent, outcome + s.thisTurn}, false
  • Abstract business complexity into separate functions, even tight 1 function interfaces such as famous standard library io.Reader, io.Writer and comfortably pass them as function arguments, unit testing and mocking will become extremely convenient (more on this topic in incoming blog post)
type Reader interface {
Read(p []byte) (n int, err error)
type Writer interface {
Write(p []byte) (n int, err error)
func JSON(reader io.Reader) (ABI, error) {

Extra resources on topic Value vs Pointer vs Function in Go:


Go was not designed to be primarely Object Oriented language in the way languages such as Java/PHP/C++ were but the comparison is necessary because those are the languages majority of developers are coming from as fresh Gophers, bringing old solutions, techniques with them that may not necessarily be good solutions in Go environment.

Go is a combination of paradigms.

  • It satisfies majority of Object Oriented characteristics (both mainstream and original ones, as stated at the beginning of the article) to solve general software extendibility issues and provide a way for developers to design domains more naturally
  • It masters Functional/Procedural/Objects characteristics and Messaging to solve problems with concurrency and parallelism in the era of multicore CPU hardware architecture

But wait! There is more!

Are you curious how Go is used to develop blockchain peer-to-peer systems?

I wrote a fun-to-read technical eBook where you build a blockchain in Go from scratch. You convert a dummy MVP JSON database into a fully functional peer-to-peer system.

Get the first 6 chapters of the book for FREE:

Follow me on Twitter for more Go goodies:



Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store