Editor’s Note: We have taken closer looks at Go in previous posts. In this post, Shiju Varghese looks at Golang from an architect’s perspective to show individual aspects of the language that he finds extraordinary.

Everything in the world is evolving, computer programming languages too. For the last five years, we have seen the arrival of Clojure, Rust, Julia and CoffeeScript, which are all representative of a shift in application development.

Go is a new programming language that didn’t evolve or borrow from existing programming languages such as C# and Java. Go simply ignores the programming language theory. If you are coming from a C# 5.0 or Java 8.0 background and looking to Go as a more feature-rich language, you will be disappointed. Instead of focusing on academic theories and intellectual thoughts, Go focuses on real-world practices for building next-generation applications on the cloud as well as distributed and concurrent computing environments, and for system programming.

Having worked on the C# language for more than a decade, I was super excited about the design of Go when I looked at the language with a fresh and pragmatic mindset.

I’ll offer you a high level look at Go and then focus on Go’s type system and concurrency support, which are the most unique features of the language.

A Static Type Language with a Greater Level of Productivity

Go is a statically typed, garbage-collected, natively compiled programming language that mostly belongs to the C family of languages in terms of basic syntax. Go provides an expressive syntax with it’s lightweight type system and comes with concurrency as a built-in feature at the language level. Go provides performance comparable to C and C++ while offering rapid development.

If you are coming from a static type language, you already know the power of such language when it comes to performance and maintainability. While keeping Go as a static type language, it provides the productivity of a dynamic type language, thanks to Go’s surprisingly simple syntax and language design. You can say that Go is a modern C with a lot of productivity. If you are coming from a dynamic type language, Go will solve your performance and maintainability problems while maintaining productivity.

Like C and C++, Go compiles to native machine code so that we don’t need environments such as CLR and JVM to run Go applications. This will give you a lot of advantages when you are distributing your applications through application containers such as Docker.

Another advantage of the Go compiler is that it compiles programs very quickly. That helps particularly when compiling large applications.

Simple and Minimalistic Language with Pragmatic Design

If you look deeply into Go’s design, it will surprise you because of its pragmatic, simple and minimalistic approach. For example, Go’s types are exported to other packages if the name starts with an uppercase letter. Types that start with lowercase will not export to other packages and the access will be restricted with the same package.

Go comes with very limited features, but it will not hurt your productivity, as all features required to build large applications are included. Go’s type system is very simple, following a pragmatic design that offers code reusability, productivity and extensibility.

Go Type System is Awesome

If you are coming from other programming languages, try to look at Go with a fresh mind so you can experience the power and pragmatic design of the Go language design. Go does not provides class keyword and its object-orientation is different from other object-oriented programming languages. If you are looking for something similar to classes in Go, you’ll find Go’s type struct. Go does not support inheritance in its type system, but it supports composition of types. If you are a pragmatic developer rather than into academics, composition over inheritance will excite you.

If you want to implement an interface into a struct type, you don’t need to explicitly implement the interface type along with the struct type definition. Instead, you just need to implement the methods defined in the interface into the struct type.

Here’s a sample that demonstrates the Go type system with interface and struct. It also explores type embedding for type composition.

Code Listing – 1

package main import "fmt" type People interface { SayHello() ToString() } type Person struct { name string age int phone string } //A person method func (p Person ) SayHello() { fmt.Printf("Hi, I am %s, %d years old

", p.name, p.age) } //A person method func (p Person) ToString() { fmt.Printf("[Name: %s, Age: %d, Phone: %s]

", p.name,p.age, p.phone) } type Student struct { Person //type embedding for composition university string course string } type Developer struct { Person //type embedding for composition company string platform string } //Developer's method overrides Person's SayHello func (d Developer) SayHello() { fmt.Printf("Hi, I am %s , %d years old, developer working on %s for %s

", d.name,d.age,d.platform,d.company) } func main() { alex := Student{Person{"alex", 21, "111-222-XXX"}, "MIT","BS CS"} john := Developer{Person{"John", 35, "111-222-XXX"}, "Accel North America", "Golang"} jithesh := Developer{Person{"Jithesh", 33, "111-222-XXX"}, "Accel North America", "Hadoop"} //An array with People types peopleArr := [...]People{alex, john,jithesh} //Iterating through the array of People types and call methods. for n, _ := range peopleArr { peopleArr[n].SayHello() peopleArr[n].ToString() } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 package main import "fmt" type People interface { SayHello ( ) ToString ( ) } type Person struct { name string age int phone string } //A person method func ( p Person ) SayHello ( ) { fmt . Printf ( "Hi, I am %s, %d years old

" , p . name , p . age ) } //A person method func ( p Person ) ToString ( ) { fmt . Printf ( "[Name: %s, Age: %d, Phone: %s]

" , p . name , p . age , p . phone ) } type Student struct { Person //type embedding for composition university string course string } type Developer struct { Person //type embedding for composition company string platform string } //Developer's method overrides Person's SayHello func ( d Developer ) SayHello ( ) { fmt . Printf ( "Hi, I am %s , %d years old, developer working on %s for %s

" , d . name , d . age , d . platform , d . company ) } func main ( ) { alex : = Student { Person { "alex" , 21 , "111-222-XXX" } , "MIT" , "BS CS" } john : = Developer { Person { "John" , 35 , "111-222-XXX" } , "Accel North America" , "Golang" } jithesh : = Developer { Person { "Jithesh" , 33 , "111-222-XXX" } , "Accel North America" , "Hadoop" } //An array with People types peopleArr : = [ . . . ] People { alex , john , jithesh } //Iterating through the array of People types and call methods. for n , _ : = range peopleArr { peopleArr [ n ] . SayHello ( ) peopleArr [ n ] . ToString ( ) } }

In the above sample code, we first declare an interface type named “People” with two methods – SayHello and ToString. We create a struct type Person and add two methods, SayHello and ToString. Unlike Java and C#, you don’t need to explicitly state that you are going to implement an interface into a type.

In Java, we would have to do the following to implement an interface:

Code Listing – 2

public class Person implements People{ //implementations here } 1 2 3 public class Person implements People { //implementations here }

In C#, we would have to do the following to implement an interface:

Code Listing – 3

public class Person : People{ //implementations here } 1 2 3 public class Person : People { //implementations here }

In Go, explicit declaration of interface implementation is not required and you just need to implement the methods defined in the interface into your struct type where you want to implement it. This simple design gives you a lot of advantages when it comes to building loosely-coupled systems in a productive manner.

After defining the struct type “Person”, we are embedding the type “Person” into struct type “Student” and “Developer”. In Go, composition is the preferred way over inheritance where type embedding is the way to implement composition. The design approach of using composition over inheritance will give you a lot of practical advantages when you build complex object-oriented systems. Since we are embedding type Person into type “Student” and “Developer”, the methods defined in the type “Person” will automatically be available for the type “Student” and “Developer”. You may feel that this is like inheritance, but it is true composition which has a lot of advantages over inheritance. We also override the method SayHello for type “Developer”. In the main function, which is the entry point of our sample program of Code Listing -1, we create an Array of People interface type and assign one “Person” object and two “Developer” objects, and finally iterate through the Array and call the methods.

alex := Student{Person{"alex", 21, "111-222-XXX"}, "MIT","BS CS"} john := Developer{Person{"John", 35, "111-222-XXX"}, "Accel North America", "Golang"} jithesh := Developer{Person{"Jithesh", 33, "111-222-XXX"}, "Accel North America", "Hadoop"} //An array with People types peopleArr := [...]People{alex, john,jithesh} //Iterating through the array of People types and call methods. for n, _ := range peopleArr { peopleArr[n].SayHello() peopleArr[n].ToString() } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 alex : = Student { Person { "alex" , 21 , "111-222-XXX" } , "MIT" , "BS CS" } john : = Developer { Person { "John" , 35 , "111-222-XXX" } , "Accel North America" , "Golang" } jithesh : = Developer { Person { "Jithesh" , 33 , "111-222-XXX" } , "Accel North America" , "Hadoop" } //An array with People types peopleArr : = [ . . . ] People { alex , john , jithesh } //Iterating through the array of People types and call methods. for n , _ : = range peopleArr { peopleArr [ n ] . SayHello ( ) peopleArr [ n ] . ToString ( ) }

If you look deeply into the code example we have demonstrated in the Code Listing -1, you will understand the power of Go’s type system. Go’s type system is the unique and most compelling feature of Go compared to many existing programming languages.

We will explore the features of the type system in upcoming posts about Go.

Concurrency is Built In Feature at Language Level

Our computers has evolved over the last decade. In the past, we programmed against computers with single CPU cores. But today, our servers have 32, 64, 128 and many more CPU cores, but we are still using programming languages and technologies designed in the era where only single core machines were available. These days, most programming languages provide support for concurrency through libraries and frameworks, but not at the core language level. In Go, concurrency is a first-class citizen in the core language. Go introduces Goroutines, which lets you run functions concurrently. You can communicate and pass values between Goroutines using Channels. Goroutines and Channels are great features of Go that let you leverage concurrency and parallelism in your applications with a more secure and efficient manner. Some of Go’s standard libraries have concurrency built in using Goroutines. For an example, the standard library “net/http” which provides support for programming on HTTP handles incoming requests concurrently using Goroutines.

Go Packages

Like other features of Go, packages also provide simplicity. Go programs are organized into file directories called packages, which enables code reusability across Go applications. We can import Go packages using the import keyword which lets you reuse code into your applications. In the Code Listing – 1, we import a package “fmt” from the standard library. By simply using the import statement, we can import packages from both the built in standard library and GOPATH, which is your Go project root directory in local machine. We can install third-party Go packages by using “Go get” command in the terminal.

Unlike other package management systems such as NPM, NuGet and RubyGems, Go does not provide a centralized repository for Go packages. The Go package management system is designed to work with modern scenarios where developers share source through repositories hosted on Github.

The following command in the terminal will install a third-party package “mgo” into your GOPATH which can be used across projects put on the GOPATH directory.

go get gopkg.in/mgo.v2

After installing the third-party package, just put the import statement in your programs for reusing the code, as shown below:

import ( "gopkg.in/mgo.v2" ) 1 2 3 import ( "gopkg.in/mgo.v2" )

Summary

Go is a surprisingly a simple programming language. The type system of Go enables code reusability through type embedding which promotes composition over inheritance. In Go, concurrency is a first-class citizen in the core language, letting you build high performance applications for modern computing environments. Go is a great language for building applications for distributed, concurrent and Cloud computing environments.

Shiju Varghese is a Solutions Architect who specializes in Cloud Computing solutions. He currently works as a Technical Architect for Accel Frontline.

Feature image via Flickr Creative Commons.