Today I thought I’d look into static typing of variables, as it’s a fundamental quality of Go as a language.
So, in languages like Python, you could very easily do the following with variables:
>>> a = "bc"
>>> a
'bc'
>>> a = 3
>>> a
3
In languages such as these, a variable is just a container for stuff. You can change what stuff goes in mid-stream, dynamically changing the type of the variable.
In comparison, Go is a statically typed language. You can either declare a variable explicitly with its type for use later (var x int
for integer) or inferred at creation time (x := "hello"
for a string containing “hello”) So of course I’m going to try the same exact hijinks as above:
package main
import "fmt"
func main() {
a := "bc"
fmt.Print(a)
a = 3
fmt.Print(a)
}
Trying to build or go run prog.go
spits out an error message:
./prog.go:8:4: cannot use 3 (type untyped int) as type string in assignment
Okay. But what happens if we try to dynamically reassign to the existing variable a
?
package main
import "fmt"
func main() {
a := "bc"
fmt.Print(a)
a := 3
fmt.Print(a)
}
Unsurprisingly, we get the same error as before, but also a complaint about trying to assign a variable using the type-inferring :=
operator:
./prog.go:8:4: no new variables on left side of :=
./prog.go:8:4: cannot use 3 (type untyped int) as type string in assignment
OK, so what if we redeclare the variable as a different type after we use it?
package main
import "fmt"
func main() {
a := "bc"
fmt.Print(a)
var a int
a = 3
fmt.Print(a)
}
No dice:
./prog.go:8:6: a redeclared in this block
previous declaration at ./prog.go:6:2
Just as an aside, what I do really like about the stack trace here is that it doesn’t just bomb out with “type mismatch” or whatever. It’s actually quite friendly - it tells us that on line 8, position 6 a redeclaration of a variable occurs, and even where it was originally declared.
But why all this hassle about typing? I just want to cram stuff into my variables
The reason for static typing is, unsurprisingly, efficiency of execution. Because the program isn’t constantly checking the type of information in variables that it processes to see what it can do with them, it’s simply faster to run. This plays right into the fact that Go is a compiled language, so all of that checking and translation into machine code is done once at the compilation stage, not every single time the program is invoked. Efficiency!
So, while it makes little sense to have your little script that you use to sift through information that you pass it on occasion written in Go, if you’re having something chomp on lots of data or be invoked lots of times, the efficiencies become clear.
But there isn’t one type of programming paradigm that’s dominant at the expense of others. If all you have is a hammer, then everything looks like a nail. You’re going to need the right tool for the right job, and statically typed and compiled languages like Go are the right tools for particular jobs.
Getting information out of variables
Let's declare a few variables and use Go's syntax of printing information about them (fmt.Printf()
):
package main
import "fmt"
var (
DemoString string = "Hello, world!"
Boolean bool = true
FloatingPt float32 = 1234.567
)
func main() {
fmt.Printf("DemoString is a variable of type: %T. It has the value of %v", DemoString, DemoString)
fmt.Printf("Boolean is a variable of type: %T. It has the value of %v", Boolean, Boolean)
fmt.Printf("FloatingPt is a variable of type: %T. It has the value of %v", FloatingPt, FloatingPt)
}
This gets you:
DemoString is a variable of type: string. It has the value of Hello, world!
Boolean is a variable of type: bool. It has the value of true
FloatingPt is a variable of type: float32. It has the value of 1234.567
It's important to note here that you cannot print the name of a basic declared variable in Go. As the human-readable names are discarded at compile time, you're left with just their values and types. That's why in the above example I had to manually put the name in to the string I was printing, and then get the value and type from the program itself. Also notice that the interpolation proceeds left to right with references at the end of the line, so for every interpolation you have to declare the variable to be used at the end of the expression.
References and further reading
- A Tour of Go - Basic Types
- I Finally Understand Static vs Dynamic Typing and You Will Too!
- Cover image: Photo by Mika Baumeister on Unsplash
Tomorrow, who knows? It’s a Friday, so I might be doing this with a glass of wine…
Top comments (0)