YURKOL Ltd - Custom Software and Cloud Architectural Solutions for Modern Businesses

Scope and Closures in Go.

When interviewing Go developers I often find lack of understanding of closures by them. When asked about closures, some answers are like "it's when a function is defined in another function". Such is only a partial reflection of the concept. First things first: to fully grasp the concept of closure, one has to understand the idea of the scope or, more precisely, lexical scope.

In Go (and other programming languages), scope means the portion of the program text in which the variable can be accessed. Scope is a source-code level concept, and a property of name bindings, particularly variable or function name bindings — names in the source code are references to entities in the program — and is part of the behavior of a compiler; scope delimits the contiguous region where objects, functions and other identifiers (like variables and constants) can be accessed.
Important - this is a source-code level concept, in runtime this idea is implemented with call stack etc. but I don't wish to bore the reader.

Continuing the topic of program text, let's introduce a concept, which is very close to the concept of the scope - the block. Each place in the program text, where declaration occurs is called block. In Go and other C-like languages every set of braces {} defines another block, and/or (to some extent) the scope, so we're deliberately going to use these terms interchangeably.

Let's have a look at an example:

File go-sketches.go

Outer and inner code blocks in Go

In this code snippet there are two scopes (or blocks): first one is a scope of WithBlocks function. It starts in line 24 and ends in line 32. Every function has it scope. Besides, every time we're using a control structure or a loop we create a block of code (and scope respectively). In our example, there is an if block, which starts in line 26 and ends in line 30. In relation to the scope of WithBlocks this is the inner scope. Before running this snippet - guess, what would be an output?

It would be 10 5 10.
We define var x in line 25, - outer scope, that is scope of WithBlocks function, - and assign it value 10. Then, as we execute an if instruction, the condition is true, so instructions inside this, inner code block are executed. Notably, we can access an identifier defined in any outer block from within inner block. And instruction in line 27 displays the value of variable x from the outer block which is 10.
After that, in line 28, we define a new variable with the same name, and assign it value of 5. Then we output this value with an instruction in line 29. Then the flow of excution leaves the inner block and enters the outer one (closing curly brace).

Here we've got two variables with the same name in two different scopes. This is called shadowing. Here I did like this exclusively for demo purposes; you should avoid this in real programming. It is considered as a bad practice.

In line 31, we output the value of the var x, which belongs to outer scope - scope of a calling function WithBlocks. Expectedly, the value of 10 is displayed.

Using the idea of nested scopes, we can define a function inside another function.

Example:

File go-sketches.go

Closure function in Go

Here, inside of Outer function we define another function and assign it to a variable with name inner.
Functions in Go are first class citizens, thus they can be assigned to a variable and returned from another function - exactly what we're doing here. The inner function doesn't declare any variable in its own scope, but has an access to the outer scope. From there it fetches variable x and elegantly outputs it, than outputs this variable's value incremented by 2 . And this it: our inner function is none other than closure:

it is defined in another function and it has access to the scope of parent function even when parent function is exited.

Let's try our closure:

File scetches_test.go

Testing closure function in Go

Running this test will give us expected output: 25   27.

In the next article I'm going to demonstrate some example of practical use of closures.


Actually need to harness the power of Go programming language for your own organization?
Contact me and I'll get back to you shortly.