CategoryGo

More on Channels in Go

In our last post, we talked about channels in Go. In this post we will go a little deeper into the concurrency features of Go has. Before we move on, we should briefly look at an overview of unbuffered and buffered channels.

Reviewing Channels

As we mentioned in the last post, by default channels are unbuffered. This means that they will only accept incoming values when there is a value that is being sent. The best way to look at this kind of behavior is to imagine train tracks. Imagine there are two parallel tracks that combine into one single track. In an unbuffered world, these tracks will always switch when there is exactly one train ready to cross. This means that if a train is coming from the right side, then the tracks will switch to that side. If a train is coming from the left side, then the tracks will switch to that side.

The trouble starts when we have multiple trains coming to the fork at once. The only way to resolve this problem is to use a buffering system. In this situation, one train will stop and wait while the other one crosses. If the buffer is increased then more trains can cross this fork without crashing into one another.train-switch

Like the metaphor, a buffered channel allows the program to send a specified number of values into a channel before they need to be received. Lets look at an example of this.

This example is very much like our metaphor. Both of our strings are trying to go into the channel before the channel is received. If we didn’t use a buffer then this would fail and cause a deadlock. A deadlock in Go is what happens when the switch between our two forking tracks can not decide which side to let through. As a result, both trains get stuck at the fork indefinitely.

Select in Go

Lets now look at another feature of Go’s concurrency model; Select. Select in Go allows a goroutine to wait for multiple communication operations to occur. The select operation will block the code until one of its cases is matched. It is a bit like a switch statement in this way.

If we have two or more channels and we want all of them to resolve at the same time we can use a select statement. Here is an example.

In this example, we have two channels both which are unbuffered. We run two anonymous functions concurrently to one another using goroutines. In these functions we pass a string to each of the channels. We then use our select operator to print out this message. We use a for loop to iterate twice through our select operator so that both cases are printed.go-channel

Like a switch statement, our select operator can also have a default case. This default case will try to execute when no other case is ready. Here is a simple example.

This example is pretty self explanatory. Based on the time after execution various events will happen as a result of the select operator.

Conclusion

In this post, we talked further about Channels and we introduced the select operator. We also talked further about channel buffering and how it works and we touched on deadlocks. In our next posts, we will start to look at the built in Http-server in Go using all of the concepts we’ve learned thus far.

Channels in Go

In the last post, we looked at goroutines. Goroutines allow us to deploy multiple threads in a concurrent fashion. In this post, we will be looking at channels in Go. Channels in go let these goroutines communicate with one another.

Channeling and Piping

With goroutines, we have the ability to do multiple things at once. However, we do not have the ability to synchronize the threads effectively when we want them to communicate. This is where channels come in. Channels allow us to synchronize the execution of these concurrently running functions. They also give us a mechanism by which we can pass values from one thread to another safely.go-channel

Channels have several different characteristics: the type of data, the buffer size, and the direction of communication. You may specify all of these features by using the built in channel operator <-. Lets look at some basic examples.

As with many of the other complex data structures in go, we can use the make operator to create a channel. We write chan followed by the type of information we want to send. We can further change the definitions of the channels by adding the arrow operator <- before or after chan. This arrow operator tells us which direction the channel flows in; placing it before indicates that the channel will be read only and placing it after makes the channel write only. Finally, we can indicate the buffer size by passing a second argument to the make statement.

Channels are first class elements in Go. This means that they can be used almost anywhere; in struct fields, function arguments, function return statements, and even other channels. Lets look at some sample code of this.

Using Channels in Go

Now that we have a basic understanding of what channels are, let us actually see them in action.

In this example, we create a channel in the main function body. This channel takes in a Boolean value and has no specified buffer. We send the channel into our function which is a goroutine, this goroutine returns true and then back in the main function we wait for a value to be passed through the channel. Unlike our examples from last post, we don’t need to add a fmt.Scanln() function at the end because the program will only end after the channel reads a value from the goroutine. This happens because our channel has no specified buffer.go-channels

In Go, all of the operations on these unbuffered channels block or stop the execution until the sender and receiver are ready to communicate with one another. If a channel has a buffer in Go, all read operations succeed without blocking if the buffer is not empty and write operations will not block if the buffer is not full. Unbuffered channels are called synchronous channels while buffered channels are called asynchronous channels. Lets look at a buffered example.

In this example, we’ve given our channel a buffer of 3. Our code will run through all of the goroutine iterations before the time.Sleep execution call. If we remove the buffer, only one iteration of the goroutine will run before time.Sleep is called. The buffer is letting all of the write operations happen without waiting for the first read. Without the buffer, the channel will only make one write before it has to read the value in the final line of code.

Conclusion

In this post, we took a look at channels in Go. We looked at unbuffered channels and we briefly looked at buffered channels. In our next posts, we will continue to look at channels and the other concurrent features in Go.  

Concurrency and Goroutines in Go

In this post, we will be looking at goroutines in Go. Go is a language that was built with concurrency in mind. Given that almost all of the computers of the modern era employ the use of multiple cpu cores, this is a natural approach. Go makes use of a special feature called the Goroutine to handle concurrency. You can use these goroutines to call on lightweight threads to run a function. Before we take a look at examples, lets talk about concurrency for a moment.

Concurrency in Computing

Concurrency is the use of independent processes that work in an asynchronous order to complete a task. There are many examples of concurrency in the real world. We can look at how trains share tracks with one another, how in multiplayer games each player can make an action independent of one another, and how society in general works with each person making their own decisions. Naturally, many things use a model of concurrency.

Logically, it makes sense to apply this type of behavior to a computer program. When you download a file, listen to an audio stream, send a message over the web, print out a document, or even type in a text editor, you are making use of concurrency in programs. Some programming languages use different methods to handle concurrency and Go is certainly no exception with it’s goroutines. 

go-routines-gopher

Examples of Goroutines in Go

The simple definition of a goroutine, is a function that is capable of running concurrently with other functions. To invoke a goroutine, we simply place the word go in front of a function execution call. Let us look at a very simple example of this.

In this example we use a for-loop to iterate through ten values (0 to 9) inside of our function. Our main function has its own thread and in a way, the main function itself runs like a goroutine. We invoke a second goroutine with our function by typing go a(0). If we were to remove the goroutine and the Scanln function call, the function would run normally and then the program would end after execution. However, because the function is running on a separate thread then the main function, if we were to remove the Scanln call and leave the goroutine, the program will terminate before the end of the function. This happens because the main function doesn’t wait for the goroutine to end before moving on to execute the rest of the code.gopher_pipe

Because goroutines are very lightweight threads, we can literally call on thousands of them in a piece of code (the average 64 bit cpu can use 100,000 goroutines at once). Let us look at an example that uses many goroutines.

In this example, we are assigning ten threads (labeled 0 to 9) to our function by using our for loop. In our function, we are iterating through ten values again, however, each time we are now stopping and waiting for a random period of time which is between 0 and 250 milliseconds before the thread continues execution. In this way, we can see the way the threads are actually running parallel and concurrent to one another. You will notice that threads that were deployed before others may end execution well after the others have finished.

Conclusion

In this post we looked at how we can spawn threads and run functions concurrently in Go. The talked about goroutines and gave a general overview of concurrency. In our next few posts we will talk about how we can send data from one goroutine to the other using channels. 

Structs and Interfaces in Go

Thus far we have looked at many of the different data types that Go comes with. While you might be able to get away with making any program using only these types; it would be extremely tedious and difficult. Certain programs reuse data shapes over and over again. Therefore, creating a custom data type will ultimately save tons of time. In this post, we will be looking at Structs and Interfaces in Go.

Structs in Go

Structs are basically a custom data type that contains a set of named fields. In a struct, each field or variable has a type and like with functions we can define multiple fields that share the same type. Consider a Person struct.

structOur Person struct contains a name, gender, and age. Above, you can see the different ways that we can use the custom type that we created with this struct. When we use the new keyword to define a variable of our type struct, we allocate memory for the fields, set each of the fields to their zero values and return a pointer (*Person). We can access fields later in the code using the dot (.) syntax.

Methods in Go

Methods are special functions that we can associate to our structs in Go. We use a special type of syntax to do this. Consider for a moment the creation of a function that prints out our instance of the person struct.

Notice that we are passing the function parameters before the name of the function in this case. This is called using a receiver. The receiver is what allows us to associate this method to the struct Person. It also allows us to call the method with the dot syntax. This type of coding is much easier to read and it allows us to ignore using the & operator. Go will automatically pass a pointer to this function.

Because the function is associated to our struct of person, we can name it something simple. Lets try creating a different type of struct.

In this example, we created a type for a square. We then created a method to calculate the area of the square and then printed that result in our main function. We can also create embedded types using structs. For example, if we wanted to extend our person struct and add a few more fields we could do so.

Notice that we are able to bind our Person struct to a field inside of our Animal struct. We can also just say that it includes person rather then adding a new field to the Animal struct. When we add the struct the second way, we can just access that field by using the type directly with the dot syntax. For example, say a is a new animal type variable, a.Person.name = "Jazzpurr" is how we would assign the field with this syntax. Also, notice that when we embed structs into other structs they inherent the methods as well.

go-methodsInterfaces in Go

Say we have multiple shape structs inside of our program and they all have methods for their areas and parameters. We can further abstract these shape methods and assign them to an interface.

In this example, we have two method names and their return value types. We define an interface in a way that is similar to a struct. However, instead of defining fields inside of the interface, we define a list of methods. These methods are methods that must be contained in a type for that type to be a part of the interface. This interface might not seem very useful, however, we can use it as an argument for a function, a field for a struct, or even to create a struct out of the interface type.
Lets look at an example of these different implementations.

In this example, we created two structs one for rectangles and one for squares. We create an interface of shapes with the area methods inside of it. We use that shape interface to create a sum of areas method. This actually makes our interface behave like a struct in that it allows us to classify a shape as a shape, though not formally. We can then calculate the area of the square and the rectangle inside of the main function and print them out. Keep in mind that this example isn’t the best use of interfaces in Go. It merely shows the types of relationships that we can create between structs, interfaces and methods in Go.

Conclusion

In this post, we looked at both Structs and Interfaces in Go. We also looked at methods and we talked about fields. In our next posts, we will start to look at go-routines and how go handles concurrency and multi threading.  

Pointers in Go

In this post, we are going to look at pointers in Go. Pointers appear in lower level programming languages. These features let us get closer to the hardware. We can see where the data is being stored in our memory. Slices, in fact, are pointers to arrays in Go. So when we mutate the length of a slice in Go, it reassigns itself to a different array behind the scenes.

Putting Our Nose on the Hardware.

We can use this type of behavior to our advantage with smaller data structures. Pointers in Go allow us to manipulate data without having to pass it from one place to another. As a consequence, we can use them when we are dealing with multiple threads and more complex data structures. We can also use them in functions. Let’s look at an example.

In this example, we have two functions, one that uses a pointer and one that doesn’t. Neither of these functions have return statements. Therefore, there is no effect from re-assigning the variable inside of the first function. The second function has an effect on our variable in main because we are passing a memory location rather then a value.

We can’t directly use arithmetic on pointers in Go. This is a consequence of Go having garbage collection. However, once we assign a value to a pointer it will continue to point to that value for the pointer’s lifetime. The only exception to this guarantee is in the case of nil pointers.

pointers-memoryPointing with Pointers

To fully understand pointers, we need to first understand how variables look behind the scenes. All variables are like boxes. Inside of these boxes are values. These boxes need to be stored somewhere, however, and that place is the memory. Because variables can have different types, the boxes also have different sizes.

In Go, we can create variables that contain these memory addresses. Basically, theses variables are pointing to the location where the boxes are being held. That is why, we call these variables pointers.

In Go, when we pass a variable to a function, we are copying the box with the value into that function. This means that the new copy of that box has a different location in the memory. If we use a pointer instead of just a normal parameter, we can pass the original box into the function. This is why in our pointer function above, we see the variable value change without a return statement.

Now that we have a grasp of pointers, lets take a look at a simple example.

Notice that in this example we use the * and the & signs for different reasons. The & before a variable lets us assign a pointer to the memory address of the variable. The * before a pointer lets us see what the pointer is pointing at. As we get deeper into Go and start to look at interfaces and structs, we will start to see pointers more and more. These other data types will help us understand why pointers are so powerful. 

Conclusion

In this post, we looked at pointers in Go. We went over the basic idea of pointers as references to memory and we looked at how go treats variables on the hardware side.  In our next few posts we will start to look at structs and interfaces and then continue on to Go-routines and channels.  

Scope in Go

When we talk about scope in any programming language, we are referring to how the code can access variables. Scope defines where a variable can be accessed based on how it is declared. Scope in Go is fairly simplistic. In this post, we will be talking about scope in Go.

Go has three specific types of variables: local variables, global variables and formal parameters. First of all, local variables are found inside of a block or function. Also, global variables are found outside of all functions. Finally, formal parameters are the variables in function definitions.

scope

Local Variables

Local variables are the most common type in Go. They can only be used by the statements that are in the block of code in which they were made. This is to say that local variables are not accessible by functions outside of their own. Look at the example below.

These variables are bound to the main function. They can’t be accessed by a function or block of code outside of the main function.

Global Variables

Global variables are typically defined outside of all functions and at the top of the program. This style of defining a variable at the top is idiomatic in Go. Global variables have a lifetime that last as long as the program runs. They also can be accessed by any function in the program that follows their declaration.

In this program, both of the functions have access to our global variable. This has its advantages and disadvantages. Consequently, any function has access to this variable which means any function can change this variable.

scopeFormal Function Parameters

Finally, we have formal parameters. These variables are treated like local variables and they gain preference over global variables. Therefore, if the global variable shares the name of a formal function parameter the formal parameter will be used. So, Let us look at an example of this.

In this somewhat nonsensical program, we have three variables that share the name, g. One is a global variable, one is a local variable and the other is a formal parameter. We are also calling the references for these variables to show that they are different. This reference notation is something we will look at closer in our next post. For now, all you need to know is that the three values are different from one another. Furthermore, each time we print the reference to g out, we are calling a different block of memory. 

Conclusion

In this post, we looked at scope in Go. We looked at local variables, global variables and formal functional parameters in Go. We touched briefly on pointers and references in this post as well. In our next posts, we will be going over Pointers and References in Go. 

Anonymous Functions in Go

Sometimes you need a function to be bound to a variable. Other times it is beneficial pass a function as an argument to another function. In this post, we will be looking at anonymous functions in Go. These anonymous functions allow us to create closures, easily pass around functions as arguments, and pass functions as returns.  

Anonymous Functions in Go

Anonymous functions are called such because they have no name associated with them. This can be very useful for code that we only want to be executed in certain situations. For instance, we can pass an anonymous function as an argument for another function. We can also make a function return another function. Let’s look at some simple examples.

In these examples, we have one function which takes a function as an argument. Our function declaration explicitly states that it takes a specific type of function. In this case, we are taking in a function that takes in a string and returns a string. This type of function, the argument function, is commonly called a callback function. 

We also have a function that returns a function. This function takes in no arguments and it returns a function that takes in an integer and returns an integer. Our return function is commonly referred to as a closure. Both of these types of functions are examples of higher-order functions in Go.

First Class Functions and Closures

Go features first-class functions. This basically means that Go treats functions as it would any data structure. You can pass functions as arguments, return them from other functions, and you can store them in variables. There are also other data structures that can be used to store functions which we will get into later. 

Let us talk about closures for a second here. A closure as its name implies is a function that closes off another function. We can use closures to specifically set the initial “environment” and have that “environment” be stored for all instances of the function.court-closure

If you look at this example, our outer function gives our inner function access to its variables. This means that those variables are only accessed by the inner function and the outer function which makes it easier to control how they are changed. Our closure is not returning a function, but it creates a closed scope for these functions and it creates a consistent initial environment. 

Conclusion

In this post, we looked at anonymous functions in Go. We talked about how we can use anonymous functions to create closures. We also looked at first class functions, higher order functions, and callback functions in Go. In our next few posts, we will talk about scope and look at pointers, structs, and interfaces in Go. 

Functional Recursion in Go

In the last post, we talked about some of the basic function types and features in Go. In this post, we are going to discuss recursion in Go and recursion in general. Recursion can be a confusing concept at first. Fortunately, recursion in Go is very straight forward. 

Recursive Functions

recursive-function

A recursive function is a function that makes a call to itself inside of itself. Recursion is very strong for certain types of algorithms. Recursive functions can be much more efficient then loops in some cases. Let’s look at an example of recursion with Go.

In this simple program, we have a recursive function which will print out an integer decremented by one until it is less than zero. When the value is less than zero, the function just breaks out of the recursion. To do this, we use an empty return statement. We can rewrite this program with a for-loop.

In this case, our programs will have identical behavior and there will be no real difference in performance at this scale. Even if we call an argument of one hundred thousand or one million, we won’t really see any differences. Ultimately, loops and recursive functions each have their pros and cons depending on the implementation. 

Thinking Recursively

The main reason why people use recursion instead of loops is to avoid destructive state changes. Notice that when we use the loop, we have to change the variable for each iteration of the loop. In our recursive example, the original value of the variable does not change because each function call creates a new one. In more complex programs, it can be beneficial to avoid destructive state changes by using recursion.

One of the more famous cases of recursion is the Fibonacci series algorithm. We can use recursive function calls to represent this infinite series.

fibonacci-recursion

In this function example, we have three different return statements. If we break down how this function works, we can see a bit more how to think recursively. Because of the if statements, if we put one or zero into the function we will get those same numbers back. The recursion takes place with numbers greater than one. If we put two into our function, we call the function again for fib(2-1) + fib(2-2). This is just like calling zero and one and then adding those two together to get one. If we put three into the function, we will call fib(3-1) + fib(3-2). We can simplify this down to fib(1) + fib(0) + fib(1). We can keep doing this with ever higher numbers.

As you can see, our Fibonacci series function is just a combination of ones and zeroes. The return we get is the value at that term of the Fibonacci series. For fib(6) we get a return of eight for example because eight is the sixth term in the series. 

Conclusion

In this post, we took a look at recursion in Go. We talked about what recursion is and how we can think recursively. Our next few posts will continue to look at the different styles of functions in Go. 

Using Functions in Go

Functions are a feature in many different languages. Functions allow us to save pieces of code to reuse at any point in our program. This makes things significantly easier for many tasks. Not only does it decrease the amount that we have to write, it also makes the code more readable. Functions in Go have many specific features that make them particularly useful.

Basic Function Styles in Go

Go supports many different styles of functions. In Go, you can create first-class functions, custom function types, function literals, and functions with multiple return values. You may also use functions as a closure and define high-order functions. We will talk about each of these types of functions one at a time as we work through this tutorial. First, let’s just look at a basic function in Go and how it is structured.

functions in goHere are two simple examples of functions in Go. Our first example just calls the fmt.Println() function inside of it which prints the string “Hello, World” then creates a new line. It takes no arguments and we can simply call it by typing its name followed by a set of parenthesis. Our addition function, allows us to pass two integer values to it. It combines these two values with the addition operator and returns that sum as an integer. 

Notice that we define the types in this function. This serves two main purposes; It allows us to make the function more readable and it makes the function type safe. In this case, our function can only accept integer values and will only return integer values. This removes any unpredictable behavior from the function. Also, we can make this function definition shorter because of its successive type information. Look at the third example for this.

Return Statements in Go and Variadic Functions

We have an explicit return statement in this function. In Go, functions won’t automatically return the last line; we must use the return operator. In this case, we return the sum. We can also use this return operator to return multiple return statements from a function. Let’s look at an example of this.

Go also can make use it’s slice abstraction when we want to pass a non-set amount of arguments to a function. This is what’s called a variadic function. Most of the core functions in Go are variadic, which means that you can pass any number of arguments to them. If we wanted to make a summation function we would use a variadic function to do this.

In this example, we use this triple dot syntax to signify that we can take an arbitrary amount of arguments. It also tells the compiler to make a slice out of this data. For our first execution of sum, we pass nine arguments to it. The function then treats these like a slice of integers. We use the range keyword to iterate through all of the values and we add them all together. We then return a single integer. 

Conclusion

In this post, we took a look at basic functions in Go. We looked at how we can use functions with no arguments or returns, functions that have arguments and/or returns and functions with multiple returns. We also looked at variadic functions in Go. In our next few posts, we will look at recursion and some of the other types of functions in Go. 

Using Maps in Go

Maps are a very powerful form of data in many programming languages. JSON or python dictionaries are good examples of maps. Maps in Go are a type of associative array as well. Associative arrays can be extremely good for data that lends itself to manipulation and queries. In today’s post, we will be looking at the various ways you can implement maps in Go.

Making Maps in Go

A map in go takes on a simple format: map[key]value. Unlike an array or slice in Go, maps allow you to choose two different types; one for the index or key and one for the value. For the key types, we can use any type that is comparable. This means that our keys can be of any type that can be used in a conditional. The value type can be of any type in the entire Go language, including another map. Let’s look at some examples.

In the second example above, we created a map called people with people’s names for keys and ages for values. We can use some of the built-in methods in Go’s core to retrieve and manipulate these data points. Note that we also used type inference to define this map with the short declaration.

Using Maps in Go

Let’s look at some of these a little closer. With our first example, we can assign a new key-value pair to the map. Our second example, lets us assign the value to a variable. Our third example, let’s use find the length of the map. The fourth example lets us delete any key-value pair that exists in the map. In our fifth example, we test whether or not a key-value pair exists in the map. We use the underscore as a filler variable. This filler gets assigned to the value under the proposed key. The ok variable is a boolean type that produces true or false if that value exists. Note that we use an underscore for this because we don’t need the value in this case.

map-in-go

The last two cases are self-explanatory, with us using a for loop with the range keyword to iterate over the map. The k variable is assigned to each key in the map and the v variable is assigned to each value. This for loop runs until the map runs out of values. Our final example just allows us to define an empty map without using the make keyword.

Maps Inside of Maps

If you want to create a map that looks more like traditional JSON then you can make a map inside of a map. Multidimensional maps allow us to create large indexes that work like databases. Let’s look at a small example.

In this example, we created a map with two string values that were each bound to a map. inside of those maps were three string values bound to three more strings. We used a multitiered for-loop to unpack this data. The value of x in the first loop iterates from the John and Jane keys. The value of y iterates through the inner value strings.  

After we have talked about interfaces and struct types in Go, we will revisit maps to talk about how we can use structs and interfaces as the key type for multidimensional maps. Interfaces and structs really simplify these types of structures. For now, just keep in mind that maps in Go can use comparable types. These are booleans, numerics, strings, pointers, channels, interfaces and structs. 

Conclusion

In this post, we looked at hash-maps in Go. We looked at some of the ways we can make these maps and some of the methods by which we can access and use the data inside of these maps. In our next few posts, we will start to look at typical functions, variadic functions and recursive functions in Go.