Go basics - Control Structures (Part 2)

Today I’m going to present two important concepts you’ll need to know for your Go journey: Objects and Concurrency. That will allow us to talk about toolkit, frameworks, ORMs and so on, in future posts.

Object-Oriented Programming (OOP)

Overview

Is Go an Object Oriented language? If we use the most simple definition of Object as an abstract data type that has state (data) and provide a behaviour (code), I say Yes.

Since there is no inheritance in Go, we need to think in terms of composition. Except for that, we can find many of the same features like:

  • methods on any type we define, with no boxing or unboxing
  • automatic message delegation via embedding
  • polymorphism via interfaces
  • namespacing via exports

Now let me introduce some concepts with examples that will illustrate it.

Pointers

Go has pointers, but no pointer arithmetic.

x := 5

y := &x

fmt.Println(*y)

Output :

5

y points to x and the value of y is obtained using a * operator. The & operator is used to get the address of a variable.

The new operator is used to allocate memory to a pointer variable.

x := new(int)

*x = 9

fmt.Println(*x)

Output :

9

Structures

Are user-define data types which contains named fields. We can think of them as “object” in Go.

We declare structures using the type and struct keyword. Individual elements of the structure are accessed using the dot operator.

In the next example I also show composition:

type Person struct {
   Name string
   Address Address
   age int
}

type Address struct {
   Number string
   Street string
   City   string
   State  string
   Zip    string
}

Note that Go makes a difference between lower case and capitals in field definitions. The letter case refers to the scope of the field.  Name and Address (above) are public variables and age is a private variable. Capital names are publicly accessible.

This example in PHP looks like:

<?php
class Person {
    public $Name;
    public $Address;
    private $age;
}

class Address {
   public $Number;
   public $Street;
   public $City;
   public $State;
   public $Zip;
}

PHP does not have type hinting at the variable definition level, only the function level.

This type hinting / scalar values gives Go an upper hand when it comes to syntax checking.

Method

We can declare methods on any user-defined type.

A method declaration in Go is just like a function, except it has an explicit receiver, declared immediately before func. This function also takes advantage of named return variables, pre-initializing them for us.

Let’s extend the structures/classes defined in the previous example

func (p *Person) Greet() {
    fmt.Println("Hi, my name is", p.Name)
}

func (p *Person) Location() {
    fmt.Println("I’m at", p.Address.Number, p.Address.Street, p.Address.City, p.Address.State, p.Address.Zip)
}

In PHP:

<?php

class Person {
    public $Name;
    public $Address;
    private $age;
 
    public function __construct($Name,Address $Address, $age)
    {
        $this->Name = $Name;
        $this->Address = $Address;
        $this->age = $age;
    }

    public function Greet()
    {
        print_r("Hi, my name is " . $this->Name);
    }

    public function Location()
    {
        print_r("I’m at "
                . $this->Address->Number 
                . " " . $this->Address->Street
                . " " . $this->Address->City
                . " " . $this->p.Address->State
                . " " . $this->Address->Zip
        );
    }
}

class Address {
    public $Number;
    public $Street;
    public $City;
    public $State;
    public $Zip;

    public function __construct($Number, $Street, $City, $State, $Zip)
    {
        $this->Number = $Number;
        $this->Street = $Street;
        $this->City   = $City;
        $this->State  = $State;
        $this->Zip    = $Zip;
    }
}

Interfaces

An interface type is defined by a set of methods. A value of interface type can hold any value that implements those methods.

package main

import "fmt"
import "math"

type geometry interface {
    area() float64
    perim() float64
}

type rect struct {
    width, height float64
}

type circle struct {
    radius float64
}

func (r rect) area() float64 {
    return r.width * r.height
}

func (r rect) perim() float64 {
    return 2*r.width + 2*r.height
}

func (c circle) area() float64 {
    return math.Pi * c.radius * c.radius
}

func (c circle) perim() float64 {
    return 2 * math.Pi * c.radius
}

func measure(g geometry) {
    fmt.Println(g)
    fmt.Println(g.area())
    fmt.Println(g.perim())
}

func main() {
    r := rect{width: 3, height: 4}
    c := circle{radius: 5}

    measure(r)
    measure(c)
}

And this how it looks in PHP

<?php
interface geometry
{
    public function area();
    public function perim();
}

class rect implements geometry
{
    public $width;
    public $height;

    public function area()
    {
        return $this->width * $this->height;
    }

    public function perim()
    {
        return (2 * $this->width) + (2 * $this->height);
    }
}

class circle implements geometry
{
    public $radius;

    public function area()
    {
        return pi() * pow($this->radius,2);
    }

    public function perim()
    {
        return 2 * pi() * $this->radius;
    }
}

function measure($geometry) {
    print_r($geometry);
    print_r($geometry->area());
    print_r($geometry->perim());
}

$r = new rect();
$r->width = 3;
$r->height = 4;

$c = new circle();
$c->radius = 5;

measure($r);
measure($c);

Concurrency

Concurrency refers not only to CPU parallelism, but also to asynchrony: letting slow operations like a database or network-read run while the program does other work.

Even though, “Concurrency is not parallelism”, if this sentence means nothing to you, I suggest to check out Rob Pike’s excellent talk on the subject. It’s a great explanation with funny examples of gophers working in parallel and concurrent, you will enjoy all 30 minutes.

Go has a rich support for concurrency via goroutines and channels. This is one of the highlights of the language.

goroutines

A goroutine is a lightweight thread of execution.

Goroutines can be described as functions which run concurrently from other functions.

They’re invoked following the go keyword. As the function is invoked it runs concurrently and the rest of the code is executed without waiting for the completion of that function.

In comparison with other languages, we can consider goroutines as “green threads“. What does it mean? Go use multiplexing strategies to group goroutines and run them in a less number of OS threads. The advantages, among others, is that you can run concurrent applications in a single core system, threads are managed by virtual machine or binary library using User space instead of Kernel space, they start faster and with a low stack that can grow based on needs, just to mention some.

Here’s a small example of a goroutine:

package main

import "fmt"

func f(from string) {
    for i := 0; i < 3; i++ {
        fmt.Println(from, ":", i)
    }
}

func main() {
    f("direct")
    go f("goroutine")

    go func(msg string) {
        fmt.Println(msg)
    }("going")

    var input string
    fmt.Scanln(&input)
    fmt.Println("done")
}

Channels

Channels are the pipes that connect concurrent goroutines. We can think on channels as process intercommunication. Go uses cooperative multitasking between goroutines. So if one routine never yields, then the other will never run.

You can send values into channels from one goroutine and receive those values into another goroutine.

We can use channels to synchronize execution across goroutines.

Channels must be created before being used, using the chan keyword.

package main

import "fmt"

func main() {
    messages := make(chan string)
    go func() { messages <- "ping" }()
    msg := <-messages
    fmt.Println(msg)
}

Since I couldn’t find a better example without the need of writing a post explaining its concepts, I bring you a simple one in Java using multi-threading:

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

class Server
{
   public static void main(String[] args) throws IOException
   {
      ServerSocket socket = new ServerSocket(9000);
      while (true)
      {
         final Socket s = socket.accept();
         Runnable r = new Runnable()
                      {
                         @Override
                         public void run()
                         {
                            doWork(s);
                         }
                      };
         new Thread(r).start();
      }
   }
   static void doWork(Socket s)
   {
   }
}

Thanks for reading! I hope you enjoy it.

See you on the next post!

Next Post

Comments

See how we can help

Lets talk!

Stay up to date on the latest technologies

Join our mailing list, we promise not to spam.