## Background on Go and Struct Initialization

Go has a special character. It differs from other attractive languages out there. Go constructors are unique too. Let's establish a baseline by comparing how other languages construct objects.

PHP

```<?php
class Point {
protected int \$x;
protected int \$y;

public function __construct(int \$x, int \$y = 0) {
\$this->x = \$x;
\$this->y = \$y;
}
}

\$p1 = new Point(4, 5);
```

```public class MyClass {

private int number = 0;

public MyClass() {
}

public MyClass(int theNumber) {
this.number = theNumber;
}
}
```

Solidity

```pragma solidity ^0.5.0;

contract Base {
uint data;

constructor(uint _data) public {
data = _data;
}
}
```

Go language doesn't enforce constructors. It constructs structs as "composite literals".

Composite literals construct values for structs, arrays, slices, and maps and create a new value each time they are evaluated.
They consist of the type of the literal followed by a brace-bound list of elements. A corresponding key may optionally precede each element.

Composite literal example:

```type Point3D struct { x, y, z float64 }
type Line struct { p, q Point3D }
```

Can be initialized as:

```origin := Point3D{}                            // zero value for Point3D
line := Line{origin, Point3D{y: -4, z: 12.3}}  // zero value for line.q.x
```

"As a limiting case, if a composite literal contains no fields at all, it creates a zero value for the type. The expressions `new(Point3D)` and `&Point3D{}` are equivalent."

You can remember it as, COMPOSING TOGETHER VALUES of different TYPES with DEFAULT VALUES if no arguments are supplied. `Type + Curly Brackets.`

Go is designed with simplicity and boilerplate-free code in mind and composite literals are precisely that, but they are unnecessarily difficult to maintain.

Why? Let me unpack my day-to-day problems with composite literals and how I like to solve them.

## Create your constructor to keep the Go codebase maintainable

### My constructor rule:

When creating a new struct, like below, `Transaction, Tx`, I immediately create a dedicated function constructor: `NewTx()`.

```type Tx struct {
Gas      uint           `json:"gas"`
GasPrice uint           `json:"gasPrice"`
Value    uint           `json:"value"`
Nonce    uint           `json:"nonce"`
Data     string         `json:"data"`
Time     uint64         `json:"time"`
}

func NewBaseTx(from, to common.Address, value uint, nonce uint, data string) Tx {
return Tx{from, to, TxGas, TxGasPriceDefault, value, nonce, data, uint64(time.Now().Unix())}
}
```

Let me walk you through my four reasons for doing this. I believe you will find it helpful.

### Reason 1 - Sensible default values are rare

#### No constructor

Let's say I don't create a dedicated constructor `NewBaseTx()`. If I had to add another attribute to the Tx struct, `MaxGasPrice`, I would have to modify tens/hundreds of files (depending on the codebase size/implementation). I am not exaggerating here. That's a very realistic estimate as I have already been in several such situations on various projects.

#### Field:value constructor

However, if I would label the constructor elements "explicitly as field:value pairs, the initializers can appear in any order, with the missing ones left as their respective zero values", the refactoring could quickly end up with a production bug, as the compiler wouldn't point out all the places I forgot to pass a new value; so that's even worse approach.

`MaxGasPrice` will accidentally be 0 by default, turning the struct into an invalid state. Don't even try to fix it with an optional setter. That's pure evil.

Generally, I don't see any value in the `field:value` constructors given any good IDE will graphically show you the names like my previous screenshot. What's your experience? Agree or do you think differently?

#### Dedicated constructor

Fortunately, I can avoid all that mess, and a large PR for my teammates, because I have control over the struct creation. `I encapsulated this responsibility into a single function.` I needed to change only one place.

Every struct deserves its constructor! Your future self will thank you during the next refactoring session :)

To be objective, one struct has default values that work like a charm, and I frequently use: `sync.RWMutex`.

```type Mutex struct {
state int32
sema  uint32
}

type RWMutex struct {
w           Mutex  // held if there are pending writers
writerSem   uint32 // semaphore for writers to wait for completing readers
}

rwm := sync.RWMutex{}
rwm.Lock()
```

Very elegant. But. I have been writing Go for 4 years, and I can't pinpoint a single struct I designed using default values solely. However, I can link to 3 PRs in the last 6 months that caused a production bug because of a missing dedicated constructor. A wrong default value was supplied as the Go compiler can't pick it up; given from a compiler perspective, the value is not missing; it thinks you didn't pass it because you wanted the compiler to use a default value.

### Reason 2 - Your code changes weekly, RWMutex doesn't

The last commit to Mutex source was in November 2019. Today is October 2021.

I don't know about you, but the latest commit in my project was like 3h ago, lol.

Point being? It would be best if you optimized for flexibility and refactoring as a team in your project. Dedicated constructors help with that.

### Reason 3 - Exported Structs and Public Libraries

Public Structs and Libraries are even more sensitive to changes. Last month I created a bug due to a missing constructor. It all came down like this...

A `Config` struct was initialized with `field:value syntax`, and I added a new attribute without a possible "sensible default."

```Config{
IsObserverEnabled: func() bool {
return false
},
IsFilteringEnabled: func() bool {
return false
},
}
```

I reviewed the entire codebase, adjusted all usages, updated tests, and made a new release version.

So far, all good. Except, when I imported the library to 3 microservices using it, I overlooked one usage, and a wrong default value sneaked in and messed up a service deployment. If only there were a dedicated `NewConfig()` constructor, the compiler would throw an error after importing the library. I would also not have to change 3 microservices, just the one `NewConfig()` function in the library!

### Reason 4 - Breaking Single Responsibility Principle (SRP)

It seems like because of the lack of boiler-plate, when developers do create the dedicated constructor, they hijack it with extra logic that doesn't belong there like `Goroutines, disk operations, DB connections.`

```func NewDatabase(cfg Config) (*DB, error) {
ctx, cancel := context.WithCancel(context.Background())

db := &DB{
// stuff
}

go db.connect(ctx)

return db
}
```

Polluting constructors make it challenging to maintain, test and use.

`A constructor should only create a new instance of the object.`

That's it. It's been like this for decades, and this principle served us well. When I call: `NewDatabase(cfg)` on some library, the last thing I expect is a DB network connection firing up inside a goroutine behind the scenes.

You can't test it, and you can't even initialize the struct before a DB connection is even possible; it's just a terrible practice. This logic belongs to a dedicated `Connect()` function, not a constructor. Two different responsibilities.

This has been my experience with Go and constructors so far.

What's yours? Let me know on Twitter:

## Get Started with Blockchain Development

Hi, I am writing an eBook on how to build a peer-to-peer system in Go from scratch!

Follow how the main protagonist Andrej, a web developer by day and a bartender by night, learns real-world use of blockchain through the growth of his new business venture: "The Blockchain Bar".