The Go Programming Language

Go is an open source programming language that makes it easy to build simple, reliable, and efficient software.
Go is expressive, concise, clean, and efficient. Its concurrency mechanisms make it easy to write programs that get the most out of multicore and networked machines, while its novel type system enables flexible and modular program construction. Go compiles quickly to machine code yet has the convenience of garbage collection and the power of run-time reflection. It’s a fast, statically typed, compiled language that feels like a dynamically typed, interpreted language.

Go was conceived in 2007 to improve programming productivity at Google, in an era of multicore processors, computer networks, and large codebases. The designers wanted to resolve common criticisms of other languages while retaining many of their useful characteristics:

  • Static typing and efficiency (like C++ or Java)
  • Productivity and ease of use (like Python or JavaScript)
  • High-performance networking and multiprocessing

The designers cited their shared dislike of C++ as a primary motivation for designing a new language. 
Go was publicly announced in November 2009, and version 1.0 was released in March 2012. Go is widely used in production at Google and in many other organizations and open-source projects.
In April 2018, the original logo (Gopher mascot) was replaced with a stylized GO slanting right with trailing streamlines. However, the mascot remained the same.

In August 2018, the Go principal contributors published two ″draft designs″ for new language features, Generics, and Error Handling, and asked Go users to submit feedback on them. Lack of support for generic programming and the verbosity of error handling in Go 1.x had drawn considerable criticism.
Go 1 guarantees compatibility for the language specification and major parts of the standard library. All versions up to the current Go 1.11 release have maintained this promise.
Each major Go release is supported until there are two newer major releases.

Implementations

Two major implementations exist:

  • Google’s Go toolchain, targeting multiple platforms including Linux, BSD, macOS, Plan 9, Windows, and (since 2015) mobile devices. The primary Go compiler became self-hosting in version 1.5.
  • A second compiler, gccgo, is a GCC frontend.

A third Go compiler, known as GopherJS, also exists. GopherJS compiles Go code into JavaScript code and enables Go to be used for frontend development.

Language design

Go is recognizably in the tradition of C, but makes many changes to improve brevity, simplicity, and safety. The language consists of:

  • A syntax and environment adopting patterns more common in dynamic languages:
    • Optional concise variable declaration and initialization through type inference (x := 0 not int x = 0; or var x = 0;).
    • Fast compilation times.
    • Remote package management (go get) and online package documentation.
  • Distinctive approaches to particular problems:
    • Built-in concurrency primitives: light-weight processes (goroutines), channels, and the statementselect.
    • An interface system in place of virtual inheritance, and type embedding instead of non-virtual inheritance.
    • A toolchain that, by default, produces statically linked native binaries without external dependencies.
  • A desire to keep the language specification simple enough to hold in a programmer’s head, in part by omitting features which are common in similar languages.

Syntax

Go’s syntax includes changes from C aimed at keeping code concise and readable. A combined declaration/initialization operator was introduced that allows the programmer to write i := 3or,s := "Hello, world!" without specifying the types of variables. This contrasts with C’s andint i = 3;const char *s = "Hello, world!";. Semicolons still terminate statements but are implicit when the end of a line occurs. Functions may return multiple values, and returning a result, err pair is the conventional way a function indicates an error to its caller in Go. Go adds literal syntax for initializing struct parameters by name, and for initializing maps and slices. As an alternative to C’s three-statement loopfor, Go’s expressionsrange allow concise iteration over arrays, slices, strings, maps, and channels.

Types

Go has a number of built-in types, including numeric ones (byte, int64, float32, etc.), booleans, and character strings (string). Strings are immutable; built-in operators and keywords (rather than functions) provide concatenation, comparison, and UTF-8 encoding/decoding. Record types can be defined with the struct keyword.
For each type T and each non-negative integer constant n, there is an array type denoted [n]T; arrays of differing lengths are thus of different types. Dynamic arrays are available as “slices”, denoted []T for some type T. These have a length and a capacity specifying when new memory needs to be allocated to expand the array. Several slices may share their underlying memory.

Pointers are available for all types, and the pointer-to-T type is denoted *T. Address-taking and indirection use the & and * operators as in C or happen implicitly through the method call or attribute access syntax. There is no pointer arithmetic, except via the special unsafe. Pointer type in the standard library.
For a pair of types K, V, the type map[K]V is the type of hash tables mapping type-K keys to type-V values. Hash tables are built into the language, with special syntax and built-in functions. chan T is a channel that allows sending values of type T between concurrent Go processes.

Aside from its support for interfaces, Go’s type system is nominal: the type keyword can be used to define a new named type, which is distinct from other named types that have the same layout (in the case of a struct, the same members in the same order). Some conversions between types (e.g., between the various integer types) are pre-defined and adding a new type may define additional conversions, but conversions between named types must always be invoked explicitly. For example, the type keyword can be used to define a type for IPv4 addresses, based on 32-bit unsigned integers.

type ipv4addr uint32

With this type definition, ipv4addr(x) interprets the uint32 value x as an IP address. Simply assigning x to a variable of type ipv4addr is a type error.
Constant expressions may be either typed or “untyped”; they are given a type when assigned to a typed variable if the value they represent passes a compile-time check.

Function types are indicated by the func keyword; they take zero or more parameters and return zero or more values, all of which are typed. The parameter and return values determine a function type; thus, func(string, int32) (int, error) is the type of functions that take a string and a 32-bit signed integer, and return a signed integer (of default width) and a value of the built-in interface type error.

Any named type has a method set associated with it. The IP address example above can be extended with a method for checking whether its value is a known standard.

// ZeroBroadcast reports whether addr is 255.255.255.255.
func (addr ipv4addr) ZeroBroadcast() bool {
    return addr == 0xFFFFFFFF
}

Due to nominal typing, this method definition adds a method to ipv4addr, but not on uint32. While methods have a special definition and call syntax, there is no distinct method type.

Interface system

Go provides two features that replace class inheritance.
The first is embedding, which can be viewed as an automated form of composition or delegation.
The second is its interfaces, which provides runtime polymorphism. Interfaces are a class of types and provide a limited form of structural typing in the otherwise nominal type system of Go. An object which is of an interface type is also of another type, much like C++ objects being simultaneous of a base and derived class.

Go interfaces were designed after protocols from the Smalltalk programming language. Multiple sources use the term duck typing when describing Go interfaces. Although the term duck typing is not precisely defined and therefore not wrong, it usually implies that type conformance is not statically checked. Since conformance to a Go interface is checked statically by the Go compiler (except when performing a type assertion), the Go authors prefer the term structural typing.

The definition of an interface type lists required methods by name and type. Any object of type T for which functions exist matching all the required methods of interface type I is an object of type I as well. The definition of type T need not (and cannot) identify type I. For example, if Shape, Square, and Circle are defined as:

import "math"

type Shape interface {
Area() float64
}

type Square struct { // Note: no “implements” declaration
side float64
}

func (sq Square) Area() float64 { return sq.side * sq.side }

type Circle struct { // No “implements” declaration here either
radius float64
}

func (c Circle) Area() float64 { return math.Pi * math.Pow(c.radius, 2) }

Both a Square and a Circle are implicitly a Shape and can be assigned to a Shape-typed variable. Informal language, Go’s interface system provides structural rather than nominal typing. Interfaces can embed other interfaces with the effect of creating a combined interface that is satisfied by exactly the types that implement the embedded interface and any methods that the newly defined interface adds.

The Go standard library uses interfaces to provide genericity in several places, including the input/output system that is based on the concepts of Reader and Writer.

Besides calling methods via interfaces, Go allows converting interface values to other types with a run-time type check. The language constructs to do so are the type assertion, which checks against a single potential type, and the type switch, which checks against multiple types.

The empty interface isinterface{} an important base case because it can refer to an item of any concrete type. It is similar to the Object class in Java or C# and is satisfied by any type, including built-in types like int. Code using the empty interface cannot simply call methods (or built-in operators) on the referred-to object, but it can store the valueinterface{}, try to convert it to a more useful type via a type assertion or type switch, or inspect it with Go’s packagereflect. Because caninterface{} refer to any value, it is a limited way to escape the restrictions of static typing, like invoid* C but with additional run-time type checks.

Interface values are implemented using a pointer to data and a second pointer to run-time type information. Like some other types implemented using pointers in Go, interface values are ifnil uninitialized.

Examples

Hello world

Here is a Hello world program in Go:

package main

import “fmt”

func main() {
fmt.println(“Hello, World”)
}

Posted in: Go

Leave a Reply

Your email address will not be published. Required fields are marked *