Type Alias vs Type Definition in Go: when to use what
Let’s start coding !!
Look at the code below and think what it prints. [%T is used to print type info]
package main
import "fmt"
type int1 = int // OPTION-1
type int2 int // OPTION-2
func main() {
var i1 int1
var i2 int2
fmt.Printf("%T, %T", i1, i2)
}
Output
int, main.int2
Interestingly, i1 prints int and i2 prints main.int2.
Why we see this output ?
i1 is an alias. Alias is a second name for an exising type and it’s just like replacing all occurences of int1 with int.
Whereas int2 is a type definition. Notice the output says: “main.int2”. What this means is int2 is a new type.
What’s the difference ?
We need to look at it from following angles:
- Behavior of operations wrt the new type
We want to test if the new types behave exactly like the original type int. To do this, we try some operations that are supported by int type.
package main
import "fmt"
type int1 = int // OPTION-1
type int2 int // OPTION-2
func main() {
var i1 int1
var i2 int2
// Check if integer operations works
i1 += 10
i2 += 10
i1 -= 5
i2 -= 5
// check if the new type needs an explicit type conversion
var i3 int = i1
var i4 int = i2
fmt.Println(i1, i2, i3, i4)
}
Output
./prog.go:21:15: cannot use i2 (variable of type int2) as int value in variable declaration
Go build failed.
This is expected based on the output of the first program. The newly defined type cannot be assigned to an int var since i2's type is not int, it’s main.int2 instead. Hence we need an explicit type cast like below and everything would just work fine.
package main
import "fmt"
type int1 = int // OPTION-1
type int2 int // OPTION-2
func main() {
var i1 int1
var i2 int2
// Check if integer operations works
i1 += 10
i2 += 10
i1 -= 5
i2 -= 5
// check if the new type needs an explicit type conversion
var i3 int = i1
var i4 int = int(i2) // NOTICE HERE !!
fmt.Println(i1, i2, i3, i4)
}
Output
5 5 5 5
2. Defining new operations/methods
Let’s try to define a method on our newly defined type.
package main
import "fmt"
type int1 = int // OPTION-1
type int2 int // OPTION-2
func (i int1) ToString() string {
return fmt.Sprintf("%d", i)
}
func (i int2) ToString() string {
return fmt.Sprintf("%d", i)
}
func main() {
}
Output
./prog.go:8:7: cannot define new methods on non-local type int
Again similar to previous example we, the code doesn’t run and we get an error. But this time the error is for the type alias instead of the new type defined using type definition.
Since this operation itself doesn’t work, we remove the method func (i int1) ToString() string
and try to run the remaining code.
package main
import "fmt"
type int1 = int // OPTION-1
type int2 int // OPTION-2
func (i int2) ToString() string {
return fmt.Sprintf("%d", i)
}
func main() {
var i1 int1
var i2 int2
fmt.Println(i1, i2.ToString())
}
Output
0 0
3. Assignment operations
We already saw one error in our second example, where a newly defined type could not be assigned to the original underlying type. Let’s look at the other side now.
package main
import "fmt"
type int1 = int // OPTION-1
type int2 int // OPTION-2
func main() {
var i1 int1
var i2 int2
const (
c1 = 5 // untyped numeric const
c2 int = 10 // typed numeric const
)
// assign untyped constant
i1 = c1
i2 = c1
// assign a typed constant
i1 = c2
i2 = c2 // LINE-23
// assign a typed var
var i int = 15
i1 = i
i2 = i // LINE-28
fmt.Println(i1, i2)
}
Output
./prog.go:23:7: cannot use c2 (constant 10 of type int) as int2 value in assignment
./prog.go:28:7: cannot use i (variable of type int) as int2 value in assignment
Go build failed.
The error messages are pretty much self explanatory.
However you must notice that i2 = c2
fails while i2 = c1
doesn’t. That’s because go does a strict type matching. So for typed constants(c2) or for typed variables (line 28), type must match whereas for untyped constants (c1), type can be inferred within the expression if it’s compatible.
Applications
Type Alias
It can simply be used to define another name (alias 😝) which can be used in place of the orignal name. When would you do that ?
When you don’t like the original type name, maybe too vebose🙈.
There can actually be valid reasons for doing this, see the “reading material” at the end.
or maybe you want to tell the world that you have written this code 🤣
package main
import "fmt"
type gaurav = int
func main() {
var leangaurav gaurav
leangaurav++
fmt.Println(leangaurav)
}
Type Definition
There might be other reasons for using type definition, but one of them is using type defintion for enum like behavior. Like this example from go spec which is slighly modified for ease of understanding. Go through the spec to read the original code.
type TimeZone int
const (
EST TimeZone = -5
CST TimeZone = -6
MST TimeZone = -7
PST TimeZone = -8
)
func (tz TimeZone) String() string {
return fmt.Sprintf("GMT%+dh", tz)
}
More reading material about type alias and type definition
Try to play with the examples yourself as there’s much more to explore.
You can find me on Linkedin 👋🏻👋🏻.