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
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
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
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.