Specifying Default Argument Values for Functions in Golang
Overview
In Ruby, you can set default argument values for a function like this:
1 | def hoge(a, b = 2) |
In Golang, however, you cannot define default arguments like the following:
1 | func hoge(a, b = 2 int) string { |
While looking into how to handle this, I came across the Functional Option Pattern.
Functional Option Pattern
The following two articles are well-known and essential reading:
- Rob Pike: Self-referential functions and the design of options at 2014-01-24
- Dave Cheney: Functional options for friendly APIs | Dave Cheney at 2014-10-17
If you split functions based on whether an optional value is set or not, the number of methods grows with each argument, which gets messy.
1 | const defaultB = 2 |
The Functional Option Pattern is a solution that takes advantage of Golang’s characteristics to resolve this kind of clutter.
Rewriting with the Functional Option Pattern
1 | package main |
You can see that the default argument is working as intended.
We define Option as a function that holds settings for *configs, and by optionally setting each value within that function, we override the default settings.
This way, you can set only the optional values you want to configure, and everything else falls back to the default values.
Just when I thought it was perfect… the tests failed.
1 | fmt.Println(reflect.DeepEqual(WithB(12), WithB(12)) // false |
Since WithB returns a function type, reflect.DeepEqual returns false.
Looking at the code for reflect.DeepEqual, it returns false when the value is a function type (reflect.Func) and is not Nil.
The comment // Can't do better than this: says it all.
https://github.com/golang/go/blob/master/src/reflect/deepequal.go#L126-L131
Adding One More Touch to the Functional Option Pattern
1 | const ( |
Now WithB returns an int-type value, and reflect.DeepEqual returns true.
The trick is to define Option as an interface, taking advantage of the fact that it can be called on any type, while defining an Apply method to overwrite configs.
The Functional Option Pattern defined in googleapis/google-api-go-client below is wonderful, so it’s a great reference.
https://github.com/googleapis/google-api-go-client/blob/master/option/option.go
Summary
I casually started looking into how to set default arguments for a function, and it took an unexpected turn that made me appreciate just how deep this topic goes.
That’s all.
I hope you find this helpful.
Specifying Default Argument Values for Functions in Golang
