Pragmatic Go

@kshitij10496

@icyflame

@dibyadas

@harishnandan

Background Check

What is Go?

  • Statically-typed language + Productivity of dynamic language
  • Fast
  • Thread-safe
  • Garbage collected
  • Concurrency primitives
  • Scalable
  • Cute Mascot

Pragmatic

How to write Go code?

  • Understanding of common properties and idioms
  • Knowledge of the established conventions for Go programming
    • Naming
    • Formatting
    • Program construction

Basics

Hello World!

  • Go programs are made up of packages
  • Programs start running in package main
  • Strings in Go are Unicode compliant and are UTF-8 Encoded

Import-Export

  • In Go, a name is exported if it begins with a capital letter

  • func test(a int) int { ... } => Not Exported

  • func Test(a int) int { ... } => Exported

  • When importing a package, you can refer only to its exported names
  • Packages can be imported using a URL!
  • import "github.com/joho/dotenv"

Functions

  • A function can take zero or more arguments.
  • The type of the parameters come after the variable name
  • func Test(a, b int) string { ... }
  • func Test(a []int, b *string) int { ... }

Functions (continued...)

  • When two or more consecutive named function parameters share a type, you can omit the type from all but the last.
  • A function can return any number of results.
  • Named return values and naked return

Basic Types

bool

string

int  int8  int16  int32  int64
uint uint8 uint16 uint32 uint64 uintptr

byte // alias for uint8

rune // alias for int32
     // represents a Unicode code point

float32 float64

complex64 complex128

Variable Declaration

  • Keyword var
  • Keyword var + Initial value
  • Short assignment operator

Safety: Variables declared without an explicit initial value are given their zero value.

Type Conversion

Unlike in C, in Go assignment between items of different type requires an explicit conversion.

Type Inference

  • When the right hand side of the declaration is typed, the new variable is of that same type.
  • But when the right hand side contains an untyped numeric constant, the new variable may be an int, float64, or complex128 depending on the precision of the constant.

for Loop

  • Go has only one looping construct; for is Go's while
  • Variable scoping

if-else Statement

  • Like for, the if statement can start with a short statement to execute before the condition.

Exercise

Implement a iterative square root function:

Given a number x, find the number z for which is most nearly x.

Perform the calculation 10 times and print each z along the way.

Tips

Tip 1: Use the guess:

z -= (z*z - x) / (2*z)

Tip 2: Starting guess:

z = 1

Switch

Go only runs the selected case, not all the cases that follow.

The cases need not be constants, and the values involved need not be integers.

Using switch as an alternate to if-else construct

Defer

A defer statement defers the execution of a function until the surrounding function returns.

However, the deferred call's arguments are evaluated immediately.

Executed in LIFO order

Data Structures

Pointers

A pointer holds the memory address of a value.

The & operator generates a pointer to its operand.

The * operator denotes the pointer's underlying value.

Unlike C, Go has no pointer arithmetic.

Structs

A struct is a collection of fields.

Struct fields are accessed using a dot.

Pointers to structs

Struct literal

Arrays and Slices

Arrays cannot be resized.

Slices are dynamically-sized, flexible view into the elements of array.

In practice, slices are much more common than arrays.

Slices are like references to arrays

Arrays and Slices (continued)

  • Appending to a slice
  • Iterating over a slice

Maps

A map maps keys to values.

The zero value of a map is nil.

A nil map has no keys, nor can keys be added.

Function Values

Functions are values too.

They can be passed around just like other values.

Function values may be used as function arguments and return values.

Function Closures

A closure is a function value that references variables from outside its body.

The function may access and assign to the referenced variables; in this sense the function is "bound" to the variables.

Exercise

Implement a fibonacci function that returns a function (a closure) that returns successive fibonacci numbers

Methods

Go does not have classes.

However, you can define methods on types.

1. Value Receivers

2. Pointer Receivers

Mix-and-Match!

Methods (continued)

When to use Pointer Receivers?

1. Modify the value the receiver points to

2. Avoid copying the value on each method call

Interfaces

An interface type is defined as a set of method signatures.

A type implements an interface by implementing its methods.

There is no explicit declaration of intent, no "implements" keyword.

Concurrency

Concurrency

Concurrency is the composition of independently executable computations or processes.

Parallelism

Parallelism is the simulateneous execution of possibly related computation.

Concurrency is not Parallelism

Concurrency is dealing with a lot of things at once.

Parallelism is about doing a lot of things at once.

Concurrency is about structure, parallelism is about execution.

Concurrency provides a way to structure a solution to solve a problem that may (but not necessarily) be parallelizable.

Concurrency + Communication

Concurrency is a way to structure a program by breaking it into pieces that can be executed independently.

 

Communication is the means to coordinate the independent executions.

 

This is the Go model and it's based on CSP (Communicating Sequential Processes)

Go supports Concurrency

Go provides:

  • concurrent execution (goroutines)
  • synchronization and messaging (channels)
  • multi-way concurrent control (select)

Goroutines

A goroutine is a function running independently in the same address space as other goroutines.

Goroutines are light-weight threads.

Channels

Channels are typed values that allow goroutines to synchronize and exchange information.

Values are sent and received by the channel operator, <-

Channels must be created using make before they are used.

Channels (continued)

Sends and receives block until the other side is ready.

This allows goroutines to synchronize without explicit locks or condition variables.

Buffered Channels

Sends to a buffered channel block only when the buffer is full.

Receives block when the buffer is empty.

Channels (continued)

Sender can close a channel to indicate that no more values will be sent.

for-range construct can be used to loop over a channel until it is closed.

Select

The select statement is like a switch, but the decision is based on ability to communicate rather than equal values.

select {
case v := <-ch1:
    fmt.Println("channel 1 sends", v)
case v := <-ch2:
    fmt.Println("channel 2 sends", v)
default: // optional
    fmt.Println("neither channel was ready")
}

select blocks until one of its cases can run, then it executes that case.

It chooses one at random if multiple are ready.

Building a Fake Search Engine

Example: Google Search

Q: What does Google search do?

A: Given a query, return a page of search results (and some ads).

 

Q: How do we get the search results?

A: Send the query to Web search, Image search, YouTube, Maps, News,etc., then mix the results.

 

How do we implement this?

A Simple Search Engine

Concurrent Implementation

What if we have a slow server?

Let us add timeouts!

Avoid timeout

Replicate the servers

Summary

In just a few simple transformations we used Go's concurrency primitives to convert a

  • slow
  • sequential
  • failure-sensitive

program into one that is

  • fast
  • concurrent
  • replicated
  • robust.

Conclusion

Concurrency is powerful.

Concurrency is not parallelism.

Concurrency enables parallelism.

Concurrency makes parallelism (and scaling and everything else) easy.

Links

Thank You

Kshitij Saraogi

@kshitij10496

Siddharth Kannan

@icyflame

Dibya Prakash Das

@dibyadas

Harish Nandan

@harishnandan

Pragmatic Go

By Kshitij Saraogi

Pragmatic Go

  • 1,796