Named and anonymous objects in Go

Michele Caci
4 min readJun 4, 2020

--

In this article I want to share some concepts related to named and anonymous types in Go with an example exercise.

The exercise

Let’s take a text that represents a drawing with rectangles inside and our objective is to count them. The input is a []string input and the rectangles are drawn using 3 characters:

  • Vertices are drawn with the ‘+ character
  • Horizontal edges are drawn with the ‘-’ character
  • Vertical edges are drawn with the ‘|’ character

Here are a few examples:

A simple input with one rectangle
A simple input with 1 rectangle
A more complex input with 5 rectangles
A more complex input with 5 rectangles

Our objective is, given any of these inputs, to count all the rectangles.

A basic solution

Let’s Go count them all

To count our rectangles we first parse all vertices and we increment if for any 4 of them they respect the following properties:

  • They form a rectangle with horizontal and vertical edges
  • The horizontal and vertical sides are properly drawn

Here is how the counting algorithm looks like in pseudo-code-like Go

Counting algorithm
Counting algorithm

Let’s get into the details and see where named and anonymous types are involved.

Vertex Parsing

The first line of our algorithm is the parseVertices function. Its duty is to search for the ‘+’ character present in the []string character matrix given in input and record its coordinates in a slice of struct{x, y int} as the code shows here:

Parsing the vertices from our input
Parsing the vertices from our input

As just mentioned, struct {x, y int} represents a coordinate type so we could give it a name using the line type coordinate struct {x, y int}, but we chose to use an anonymous struct. Let’s see a few reasons for this:

  • struct{x, y int} is already a short way to indicate a pair of coordinates
  • This structure does not any specific logic attached to it
  • When used as parameter the argument clearly states that the struct is composed of an x and a y int variable

On the the other hand it can be argued that the readability is hurt because of it and that it is better to give it a name but be aware that the anonymous struct does not collide with a named one as long as the named structure contains the same fields with the same names as demonstrating in this playground example.

Line filling check

Let’s focus on this section of the code

Code for horizontal and vertical line drawing
Code for horizontal and vertical line drawing

These two variables make use of a function called lineFilling whose signature is func lineFilling(line drawnLine) func(a, b struct{x, y int}) bool.

From this signature I want to highlight two things before explaining its behavior: the parameter type drawnLine and the return type func(a, b struct{ x, y int }) bool.

The drawnLine type is a struct type, in fact a complex one that includes a function named points that accepts two coordinates and returns the characters between them and a list of required characters.

type drawnLine struct {  points   func(a, b struct{ x, y int }) []byte  reqChars []byte}

This structure is too complex to be anonymous so and this is the main reason for why it has been named. In this case readability would be too impacted by usage of an anonymous struct that a named struct is more adapted to this context.

The func(a, b struct{ x, y int }) bool type is a function type that accepts two coordinates and simply returns true or false according to the function logic. This type is simple and can be left anonymous: it clearly states its purpose without being too verbose.

Line drawing

In a similar way the two instructions drawHorizontals(in) and drawVerticals(in) take a []string in input and returns a function that given to coordinates returns a list of characters. Here are the functions signatures:

func drawHorizontals(in []string) func(a, b struct{ x, y int }) []bytefunc drawVerticals(in []string) func(a, b struct{ x, y int }) []byte

The return type func(a, b struct{ x, y int }) []byte, like the func(a, b struct{ x, y int }) bool type, is simple and concise enough to leave it anonymous.

These functions demonstrates the explicit usage of the anonymous struct{ x, y int } as parameters; these fields are visible from signature and accessed from the two functions drawHorizontals and drawVerticals. Making the struct{ x, y int } explicit helps showing what is available in the implementation.

Parting thoughts

There are different reasons of whether to use named or anonymous types, in this article we only scratched the surface and we touched mostly abstract reasons. A more in-depth analysis can be done also on the performances to provide further reasons on which kind of type to choose. Feel free to comment on with your reasons on when to use named types and when to use anonymous ones.

It is possible to check the full code for the solution of the exercise in the github repository mcaci/rectangles-example.

--

--

Michele Caci

The story of a travelling Sicilian SW Eng living in Cote d'Azur dreaming the US and a normal life...well normal is just a word ;) - Inveniam viam aut faciam