Python type hints

After working with Go for a while, one of the biggest drawbacks to Python for me is that the types of parameters to functions and methods are completely opaque without good documentation. For example, let’s take this silly function right here: def my_func(thing1, thing2): print(thing1 + thing2) This function will happily accept strings or ints (or floats, for that matter) as input and depending on the type, will do completely separate things!...

2022-08-05

Mutexes and concurrent access in Go

Golang has mutexes (short for mutually exclusion) to manage concurrent access to a shared object via multiple goroutines. Here’s an example (taken from the excellent Go by Example: Mutexes). package main import ( "fmt" "sync" ) type Counter struct { mu sync.Mutex count map[string]int } func (c *Counter) Inc(name string) { c.mu.Lock() defer c.mu.Unlock() c.count[name]++ } func main() { cnt := Counter{count: map[string]int{"james": 0, "spartacus": 0}} var wg sync.WaitGroup increment := func(name string, n int) { for i := 0 ; i < n ; i++ { cnt....

2022-07-22

Go routines and WaitGroups

Working with Goroutines is simple. You simply pre-prend your function call with go and you’re off and running. Here’s an example which calls the expensive() function five times before exiting. package main import ( "fmt" "time" ) func expensive(id int) { fmt.Printf("Worker %d starting\n", id) time.Sleep(time.Second) // Oh, so expensive! fmt.Printf("Worker %d ending\n", id) } func main() { for i := 0; i < 5; i++ { go expensive(i) } fmt....

2022-07-18

Closures in Go

In Go, it’s pretty easy to write an anonymous function. package main import "fmt" func main() { func(s string){ fmt.Println("s is:", s) }("hello world") } Running the above code produces: $ go run main.go s is: hello world You can even assign the anonymous function to a variable like so: package main import "fmt" func main() { myFunc := func(s string){ fmt.Println("s is:", s) } myFunc("hello again, world!") } Now we get this output from the above code:...

2022-07-13

Generics in Go 1.18

In Go 1.18, we get access to Genrics. Huzzah! Here’s an basic example of how to use them: package main import ( "fmt" ) func PrintAge[age float32 | int64](myAge age) { fmt.Printf("age: %s \t type: %T\n", myAge, myAge) } func main() { var age1 float32 = 30.5 var age2 int64 = 32 PrintAge(age1) PrintAge(age2) } Running the above program gives us the below output. You can see that it happily accepted the float32 and int64 values without issue....

2022-07-12

Go defer

defer in go is used to run a function later on. Specifically, the specified function will run when the enclosing function returns. There’s no clean equivalent to this in Python that I’ve found. The quintessential example is closing a file handle as your program exits. Example package main import ( "fmt" "os" ) func main() { file := createFile("/tmp/testingdefer.txt") defer closeFile(file) writeFile(file) } func createFile(path string) (file *os.File) { fmt.Println("creating file: ", path) file, _ = os....

2021-07-20

Empty Go Interfaces

When declaring function parameters in Go, you must type the incoming data. Here’s an example: package main import "fmt" func print_stuff(s string) { fmt.Println(s) } func main() { print_stuff("Passing string!") } s string indicates that we’re passing a variable of type string into the function. This prevents us from from passing into variables of any other type. For example, this will fail with ./prog.go:10:17: cannot use 42 (type untyped int) as type string in argument to example_str if you try to pass an integer....

2021-07-11

Line beaks in file names on Linux

Today I accidentally created a file whose name had a newline character in it. I didn’t notice it when I did it, but here’s how it showed up in my shell. There was a directory whose name shared the first few characters of the filename. [22:07] james_simas@widget /var/tmp $ ls o* oops? <--- Suspicious file! oops: <--- Directory I tried to delete it: [22:07] james_simas@widget /var/tmp $ rm 'oops?' rm: oops?...

2021-02-02

Translating characters with tr

I recently was having to work with Ansible for several days to deploy changes globally across prod. I was storing my playbook limit in a file like so: [18:45] james_simas@widget ~/Downloads $ cat limit.txt host1.domain.com host2.domain.com host3.domain.com At one point, I needed to use supply the list of hostnames in BASH, but rather than having them be newline separated, I needed them to be separated by commas like this: host1.domain.com,host2.domain.com,host3.domain.com I didn’t want to modify my original files (I still needed them) and this seemed like a problem somebody else has problably solved....

2021-01-14

How to use extra_vars_path in the tower_job_template Ansible module

Today I was using Ansible’s tower_job_template module in a playbook. I needed to add extra variables to the job template, but Ansible’s public documentation of the the tower_job_template module had no examples of how to do this. I was unable to find any compelling examples on Google. I was a bit of poking around the Ansible API, it turns out this was far easier than I had anticipated. Without further ado, here’s how you use extra_vars_path:...

2020-03-19