Monday, June 8, 2015

Go Variables, Memory and Pointers

I don't agree with this popular perception about Pointers!

You love it or hate it but Pointers are back in Go! Before you lose your patience in understanding them, first things first,

Pointers = Spooky

Though you can write code even without understanding an iota of pointers but be informed that pointers empowers a developer in building an efficient system. 


"By giving the programmer control over basic memory layout, Go provides the ability to control the total size of a given collection of data structures, the number of allocations, and the memory access patterns, all of which are important for building systems that perform well."


                  --- Russ Cox


In contrast to the popular perception, pointers are not too complicated to understand if you understand a little basic of variable and memory allocation. Let us see if I'm able to simplify this:

Introduction - Variables

What happens when you declare a variable and assign it with a value? Say for example:


var i int = 101
or the same example in short form:
i := 101

As soon as the compiler encounters i := 101, it is smart enough to decipher the following:

1. Name of the variable i.e. i
2. Type of the variable i.e. integer
3. Value assigned i.e. 101.


Lifetime of a Variable

In modern programming languages, a variable is allocated with memory only when it is necessary and is deallocated (i.e. the system automatically reclaims the memory) once it concludes that the variable is no longer in use by the program. For a variable, the period of time from its allocation until its deallocation is called its lifetime.


Memory Leaks


What happens if a memory is allocated but not reclaimed? This may lead to a crash in some of the cases where a programs run for a longer time with large data sets. The specific program suffering with memory leaks can no longer fulfill allocation requests as the memory is already full. Modern languages (Java, C# & Go included) avoid memory leaks by implementing automatic garbage collection.


Memory Blocks and Addresses

In Go when we code,             i := 101

The compiler allocates specific memory block (on the Stack in above case) in RAM for the variable i that holds the value 101. 

  • Do you know what is the size of that memory location? 
  • Will the size of the memory location change if we want to store 1234567890 in place of the existing 101 in variable i ?

The size of the memory depends on the type of the variable (int in this case). So, it doesn't matter whether you're storing 1 in an int variable or a bigger value 1234567890, the size of the memory allocated is always 4 bytes. Run this code here to see this theory into action.

P.S. In case of C language, the size of memory blocks of same type may vary based on the machine configuration.

Each memory location has an address represented by a hexadecimal number [format: 0x1040a120]. If I try to simplify, it can be visually represented as:
In Go - How do You Know Whether a Variable is Allocated on the Heap or the Stack?

As per the Go Official FAQs you don't need to know this. The compiler will decide this for you. Also, it is important to note that, for garbage collection, the current implementation approach of the Go is a parallel mark-and-sweep collector (may change in future). 

Why Pointers?

Benefits of Pointers.
  1. Pointers allow different sections of code to share information easily. You can get the same effect by copying information back and forth, but performance is far better in case of pointers.
  2. Pointers enable complex "linked" data structures like linked lists and binary trees.
Source: Nick Parlante

What are Pointers?


A pointer does NOT store a simple value directly. It stores a reference to a value and that reference is an address. Let me share you a simple analogy. Suppose you've captured a home video that you don't want to share publicly on soc-media/YouTube. One of your relatives residing in another city is interested to watch that video. Now you've two popular options:

1. Send a copy of the video to him via file transfer sites.
2. Upload the video to Dropbox and share a link of that video.

The second option is more efficient than the first one because if needed, you can share the same link to multiple contacts. This is same as sharing information via pointers - as they have the address of the location where the actual value is stored.

Declaring a Pointer
var p *int
Pointers are special type of variables where compilers knows that the specific variable p (above code) has to store the address of an integer. A simplified graphical representation follows:



  • With reference to the above image, what is the output of the following code?
              fmt.Println(*p)
It prints 101 (and NOT the hexadecimal address). This is known as dereferencing or indirecting. 


You can understand the above discussion by running the following code:


package main

import "fmt"

func main() {
 i := 101
 p := &i //Short declaration
 
 fmt.Println("Value of variable i: ", i)
 fmt.Println("Value of pointer p: ", *p)
}

If you wish, the short declaration p := &i in above code snippet can be replaced by the following two lines:

             var p *int
             p = &i

Things to Remember


-- In Go, if a variable is not assigned it is automatically initialized with a default value.
          - "Zero" in case of Integers, 
          - "false" in case of Boolean and 
          - empty strings "" in case of Strings and so on. 
-- Pointer doesn't store the actual value. They store the reference.
-- The symbol * is used to derefrence pointer variable i.e. to get the actual value.
-- The operator & is used to find the address of a variable.
-- Pointer to a constant or literal value will give you compiler error. Check this code to verify.

How can I improve this post? Please share your views in the comment section.

No comments:

Post a Comment