Generics are essentially template/boilerplate code written in a form to use on the Go with types that can be added later. The main aim of generics is to achieve greater flexibility in terms of writing code with the addition of fewer lines. The concept of Generics has existed for a long time now and has been a part of many programming languages, including Java, Python, and C#, to name a few.
In the words of Alexander Stepanov, Generics are a way of creating an incremental source of catalogs of abstract code that can be either functions, algorithms, or data structures. As a part of the 1.18 release, Generics was introduced in Go for the first time.
Type Parameters in Go
Taking types and functions into account, Go brings Generics using a concept called Type Parameters. These types of parameters can be used with either Functions or Structs. Let's take a deep dive into the implementation with a few examples.
We will start by writing some boilerplate code:
Go
package main
func main() {
var radius1 int = 8
var radius2 float = 9.5
}
The above code declares two variables of type int and float in the main function, that contain the values of two radii of some circles. In the next step, we will declare a generic function that will take either of the inputs depending on its type and return to us the circle's circumference.
Go
func generic_circumference [r int | float ](radius r) {
c= 2*3.14*r
fmt.println("The circumference is: ",c)
}
So, our whole code will look something like this:
Go
package main
import "fmt"
func generic_circumference[r int | float32](radius r) {
c := 2 * 3 * radius
fmt.Println("The circumference is: ", c)
}
func main() {
var radius1 int = 8
var radius2 float32 = 9.5
generic_circumference(radius1)
generic_circumference(radius2)
}
Output:
The circumference is: 48
The circumference is: 57
The main differentiating factor in the above code is how we declare a variable r in a list and provide the list of types (int, flaot32) this variable can take depending on the arguments being passed during the function call.
Parameterized Types in Go
In the above example, we saw how using generic functions allows us to indicate what types a function can accept. Through parameterized types, Go provides one other way to describe the types we want our function to accept. Based on the previous example, here's what parameterization would look like:
Go
// Parameterized Types
type Radius interface {
int64 | int8 | float64
}
func generic_circumference[R Radius](radius R){
var c R
c = 2 * 3 * radius
fmt.Println("The circumference is: ", c)
}
In this approach, we first declare an interface named Radius, which holds the types we can pass to the function, which in the above example are: int64, int8, and float64. The next change is, how we declare our generic function. In the function declaration, using the square brackets, we pass in an instance of this Interface we declared above.
R is used in the above example to refer to any of the types that the Radius interface supports. If we invoke generic_circumference with a float64 value, then R in the context of this function is a value with type float64, if we invoke the function with an int64, then R is int64, and so on.
These two examples using type parameters and parameterized types would hopefully give you an overview of what generics can do in Go. You can definitely experiment with different implementations based on your needs and requirements and can improve your code readability with the addition of this new feature.
Generics provide as effective tools to achieve greater levels of abstraction in your code and also improve re-usability. That being said, it is important to identify the proper use cases where these can be implemented in a manner that can increase efficiency. Generics are still an early concept in Go development and it would be interesting to see how fruitful its implementations turn out to be.
Similar Reads
Channel in Golang
In Go language, a channel is a medium through which a goroutine communicates with another goroutine and this communication is lock-free. Or in other words, a channel is a technique which allows to let one goroutine to send data to another goroutine. By default channel is bidirectional, means the gor
7 min read
Encapsulation in Golang
Encapsulation is defined as the wrapping up of data under a single unit. It is the mechanism that binds together code and the data it manipulates. In a different way, encapsulation is a protective shield that prevents the data from being accessed by the code outside this shield. In object-oriented l
4 min read
Type Assertions in Golang
Type assertions in Golang provide access to the exact type of variable of an interface. If already the data type is present in the interface, then it will retrieve the actual data type value held by the interface. A type assertion takes an interface value and extracts from it a value of the specifie
2 min read
Composition in Golang
Composition is a method employed to write re-usable segments of code. It is achieved when objects are made up of other smaller objects with particular behaviors, in other words, Larger objects with a wider functionality are embedded with smaller objects with specific behaviors. The end goal of compo
5 min read
Time Durations in Golang
Operations related to time and date are a crucial part of software development (example log keeping). Go standard library provides a time package that has many functions and methods to deal with date and time. The operating system measures two types of time "Wall clock" time and "Monotonic" time. Wa
3 min read
Function Arguments in Golang
In Golang, functions are groups of statements used to perform tasks, with optional returns. Go supports two main ways to pass arguments: Pass by Value and Pass by Reference. By default, Go uses pass-by-value.Basic Terms in Parameter Passing to Functions:Actual Parameters: The arguments passed to a f
2 min read
bits Package in Golang
Go language provides inbuilt support for bit counting and manipulation functions for the predeclared unsigned integer types with the help of the bits package. .bits-package-Golang-table { border-collapse: collapse; width: 100%; } .bits-package-Golang-table td { border: 1px solid #5fb962; text-align:
6 min read
Class and Object in Golang
Every human (excluding infants) can relate to encapsulation irrespective of his/her prior knowledge of encapsulation. Do you wonder why? Simple. Recollect all the times when you were sick, and the doctor prescribed all those monstrous capsules dosage for a couple of days until you were okay again! T
6 min read
Rust - Generic Traits
Rust is an extremely fast programming language that supports speed, concurrency, as well as multithreading. In Rust, we have a concept of Generic Traits where Generics are basically an abstraction of various properties, and Traits are basically used for combining generic types for constraining types
2 min read
Command Line Arguments in Golang
Command-line arguments are a way to provide the parameters or arguments to the main function of a program. Similarly, In Go, we use this technique to pass the arguments at the run time of a program. In Golang, we have a package called as os package that contains an array called as "Args". Args is an
2 min read