Go: The Simple Programming Language

0
266

Programmer dotweb design on workstation desk_36956239_l

This is an introduction to Go, an open source programming language that makes it easy for developers to build simple, reliable and efficient software. The latest stable version of Go, the sixth major release so far, is version 1.5, which was released on August 19, 2015.

The Go programming language was developed at Google by Robert Griesemer and UNIX luminaries Rob Pike and Ken Thompson. It is an open source, high-level, compiled, highly efficient, strongly statically typed programming language. Go supports both procedural and object-oriented programming, though its object-orientation is quite different from other object-oriented programming languages like C++, Java, etc.
Some of the features of Go that we will look at are: object-orientation without class, inheritance and overloading, duck typing, closure, concurrency; built-in support for slices, maps and strings; and fast compilation, among others. Let’s install Go first. I will describe the installation steps on Ubuntu 15.04, though it can be installed on any distribution of your choice. Go can be installed either from the binary as follows:

$ sudo apt-get install golang

…or from the Go source code. I will cover the second method of installation, step-by-step.
Step 1: Install the prerequisites package. We need Git to complete the installation.

$ sudo apt-get install git

Step 2: Download the Go set-up tree. The Go source code is written in Go itself; so to create the bootstrap, we need a workable Go set-up. Download the Go 1.4 set-up tree and configure it as follows:

$ wget https://storage.googleapis.com/golang/go1.4.linux-386.tar.gz
$ mkdir $HOME/bootstrap
$ tar -C $HOME/bootstrap -xzf go1.4.linux-386.tar.gz
$ export GOROOT_BOOTSTRAP=$HOME/bootstrap/go’

Step 3: Get the Go source and compile it as follows:

$ mkdir $HOME/source
$ cd $HOME/source
$ git clone https://go.googlesource.com/go
$ cd go
$ git checkout go1.5
$ cd src
$ ./all.bash

This takes some time. If everything goes right, you should get the message ‘ALL TESTS PASSED’ along with some other responses. Now, add the Go bin directory to your PATH environment variable, as follows:

$ export PATH=$PATH:$HOME/source/go/bin'

Step 4: Check for the Go installation, by using the following command:

$ go version
go version go1.5 linux/386

Your actual output may vary, depending on your computer architecture.
Step 5: Create the GOPATH environment variable, as follows:

$ mkdir $HOME/workspace
$ export GOPATH=$HOME/workspace’

Step 6: Install the Go tool godoc, by issuing the following code:

$ go get golang.org/x/tools/cmd/godoc

Step 7: Check the godoc installation by issuing the following command:

$ godoc
usage: godoc package [name …]

This displays godoc help. Here, it’s truncated after the first line.
Step 8: Set the required environment variables for Go development, as follows:

$ export PATH=$PATH:$GOPATH/bin
$ export GOBIN=$GOPATH/bin

Step 9: Add all the export commands executed so far in the $HOME/.bashrc file to make them permanent. Now, log out and log in to get all the environment variables updated.

Our first Go program
Let’s write our first Go program, a simple implementation of a stack data structure of integers, i.e., a ‘last in, first out’ list of integers. In this version, I have intentionally avoided all the bells and whistles of the Go language in order to help readers first understand the basics. We will update our program gradually to learn different concepts of the Go language.
Go code is organised in packages. A package can span over multiple .go files. We have two files in this example— the stack package in $GOPATH/src/gostack/stack/stack.go, and the main package, which contains the main() function, the entry point of our program in $GOPATH/src/gostack/gostack.go. Let’s go through our stack.go code first.

$GOPATH/src/gostack/stack/stack.go
// The code in this file belongs to the ‘stack’ package
package stack
// Import the required packages, here only ‘error’
import “fmt”
// C reate a ‘Stack’ type, which is a slice of integers
type Stack []int
// ‘Push’ function to push item onto the stack given as argument
func Push(stack *Stack, item int) {
*stack=append(*stack,item)
}
// ‘Pop’ function to pop item from the stack given as argument
func Pop(stack *Stack,item *int) bool {
if len(*stack)==0 { // len() returns the no of elements in a slice
fmt.Println(“Pop:: The stack is empty”)
return false
}
// remove the last element from the slice in item
*item=(*stack)[len(*stack)-1]
// creates a new slice by taking the ele from first to second last
*stack=(*stack)[:len(*stack)-1]
return true
}
// ‘Show’ function to display the content of the stack
func Show(stack Stack) {
if len(stack)!=0 {
fmt.Printf(“[ “)
for _,item := range (stack) {
fmt.Printf(“%v “,item)
}
fmt.Printf(“] “)
} else {
fmt.Println(“Show:: The stack is empty”)
}
}

The first go statement states the package name ‘Stack’, which our code belongs to. Then we need to import a set of built-in or custom packages that are needed in our program; here, only the fmt package, required for formatted I/O, has been imported. Now, we have created a custom type ‘Stack’ which is equal to a slice of integers. We have written three functions to operate on a stack — Push(), Pop() and Show(). The Push() function takes a Stack pointer and an integer item to push onto the stack. Since a slice, unlike an array, can grow indefinitely, we skipped the overflow check. The Pop() function takes a Stack pointer and an integer pointer item, where the popped item is returned. It returns a Boolean value to indicate the success or failure of the operation. The Show() function takes a stack of value type. It prints the values present in the stack to the console.

Now let’s see our main package, shown below:

$GOPATH/src/gostack/gostack.go
// The code in this file belongs to the 'main' package
package main

// import our 'stack' and other required packages
import (
"gostack/stack"
"fmt"
)

// The 'main' function, entry point of our program
func main() {
var myStack stack.Stack
var item int
// show the empty stack
stack.Show(myStack)

// try to pop from the empty stack
if stack.Pop(&myStack,&item) {
fmt.Printf("\nThe Popped item=%d\n",item)
}

// push 10,20 into the stack
stack.Push(&myStack,10)
stack.Push(&myStack,20)

// show the stack
stack.Show(myStack)

// pop from the stack
if stack.Pop(&myStack,&item) {
fmt.Printf("\nThe Popped item=%d\n",item)
}

// show the stack
stack.Show(myStack)
}

The first line states the package name ‘main’. Then we import two packages, previously written ‘stack’ and built-in ‘fmt’. Note that the custom package’s ‘stack’ name is mentioned relative to the $GOPATH/src directory and it’s the directory name of the package source, not the file name.First, we create a variable stack of ‘stack’ type from the stack package. It takes the form of: <package-name>.<type-name>. One more variable item of the int type created for Pop() call. The rest of the code is self-explanatory. Now, let’s compile and execute the program, as follows:

$ cd $GOPATH/src/gostack
$ go build
$ ./gostack
Show:: The stack is empty
Pop:: The stack is empty
[ 10 20 ]
The Popped item=20
[ 10 ]

We don’t have class or inheritance in Go. We have methods and interfaces. Let’s understand methods first. A method is a function associated with a particular type. We have changed our functions to methods by shifting the stack reference from the argument list to Go receiver notation just after the func keyword. So, the set of three methods Push(), Pop() and Show(), forms an interface. Any type having the same interface, i.e., set of methods with the same signature as these three, is type compatible in Go. An empty interface is represented by interface{}, which is satisfied by any type. That’s why we have changed our item type to interface{} from int so that our stack can handle any type of data this time. Now, we can treat our stack as an object rather than normal variable, and call the operations as methods rather than simple functions. In Go, multiple values can be returned from a function. The Pop() function is modified to take advantage of that. In case of a failure, apart from the popped item, we also return an error.
Now, let’s modify the program to make it object-oriented in the Go way.

$GOPATH/src/gostack/stack/stack.go)
// The code in this file belongs to the 'stack' package
package stack
import (
"errors" // import the 'error' package for error reporting
"fmt" // import the 'fmt' package for displaying output
)
// Create a 'Stack' type, which is a slice of interface{}
type Stack []interface{}

// 'Push' function to push item onto the stack given as receiver
func (stack *Stack) Push(item interface{}) {
*stack=append(*stack,item)
}
// 'Pop' function to pop item from the stack given as receiver
func (stack *Stack) Pop() (interface{},error) {
if len(*stack)==0 { // len() returns the no of elements in a slice
return nil,errors.New("Pop:: The stack is empty")
}
// remove the last element from the slice in item
item:=(*stack)[len(*stack)-1]
// creates a new slice by taking the ele from first to second last
*stack=(*stack)[:len(*stack)-1]

return item,nil
}
// 'Show' function to display the content of the stack given as receiver
func (stack Stack) Show() error {
if len(stack)!=0 {
fmt.Printf("[ ")
for _,item := range (stack) {
fmt.Printf("%v ",item)
}
fmt.Printf("] ")
return nil;
} else {
return errors.New("Show:: The stack is empty")
}
}

We have changed our main accordingly. This time, we have used multiple assignment notations to copy the data as well as error value returned from Pop().

$GOPATH/src/gostack/gostack.go
// the code in this file belongs to the ‘main’ package
package main
// import our ‘stack’ and other required packages
import (
“gostack/stack”
“fmt”
)
// the ‘main’ function, entry point of our program
func main() {
var myStack stack.Stack

// show the empty stack
if myStack.Show()!=nil {
fmt.Println(“Show:: The stack is empty”)
}
// try to pop from the empty stack
if item,err:=myStack.Pop(); err==nil {
fmt.Printf(“\nThe Popped item=%v\n”,item)
}else{
fmt.Println(“Pop:: The stack is empty”)
}
// push 10,20 into the stack
myStack.Push(10)
myStack.Push(20)
// show the stack
myStack.Show()

// pop from the stack
if item,err:=myStack.Pop(); err==nil {
fmt.Printf(“\nThe Popped item=%v\n”,item)
}else{
fmt.Println(“Pop:: The stack is empty”)
}
// show the stack
if myStack.Show()!=nil {
fmt.Println(“Show:: The stack is empty”)
}
}

Now, it’s time to add exception handling to our program. We have modified our Pop() method to demonstrate how exception handling works. We have panic() and recover() built-in functions. A detailed description of these functions is beyond the scope of this article. We will only describe our own use case here. If Pop() method is called on an empty stack, we generate a panic with a user-given message. By default, panic gets propagated through the call stack of functions. But, we want to capture it in the same function and handle it. At the beginning of the Pop() we have called an anonymous function, i.e., a function without name. But this doesn’t get executed immediately because of the defer keyword. This is called a deferred function, which gets executed at the end of the function before returning to the caller. That means that just before leaving the Pop() function, we check if any panic has been generated, and if so, we print the panic message to the console.

$GOPATH/src/gostack/stack/stack.go
// ‘Pop’ function to pop item from the stack given as receiver
func (stack *Stack) Pop() (item interface{},e error) {
e=errors.New(“Empty stack”)
defer func() {
if ret:=recover(); ret!=nil {
fmt.Printf(“%v\n”,ret)
}
}()

if len(*stack)==0 { // len() returns the no of elements in a slice
// call panic() with the error msg
panic(“Pop:: The stack is empty”)
}
// remove the last element from the slice in item
item=(*stack)[len(*stack)-1]
// creates a new slice by taking the ele from first to second last
*stack=(*stack)[:len(*stack)-1]
return item,nil
}

In the next article on Go, we will discuss concurrency support along with a suite to test a Go program.

LEAVE A REPLY

Please enter your comment!
Please enter your name here