How to cleanly add an argument to a function - go

I have a function that's called quite a few times. How do I now add an additional parameter to that function without having to modify all the call-sites (essentially intruding the default value there and adding a bunch of noise) as well as keeping type safety?
All the languages I have previously used either support default arguments or overloading, so I am quite lost as to how I would do that.

Go doesn't have default arguments, neither it has function overloading. I think, the best you can do without changing the rest of the code is:
Rename the function Func() to FuncWithNewArg()
Add a new argument to FuncWithNewArg()
Create a new function named Func() with the original signature. Func() will call FuncWithNewArg() passing all its argument plus the default value for the new one.

The only way to add an optional argument to a function in Go is with a variadic function. As long as your function doesn't already have any variadic variables, you can add one without requiring all the existing callers to update. However, this does change the function signature, so if you have anything depending on that signature (i.e. assigning the function to a variable), such things may break.
To illustrate, suppose your function is:
func Foo(count int) error {
// do stuff
}
You could add an optional variadic variable at the end:
func Foo(count int, optional ...string) error {
// do stuff
}
You then access the optional variable as as a slice of the designated type ([]string in this case).
Now Foo() can be called as either Foo(3) or Foo(3, "bar").
Actually, it can be called with any number of arguments, so long as they match the type of the variadic variable. I.e. Foo(3, "bar", "baz", "qux") is also valid.
A function can take only a single variadic variable, and it must be the last one. This means you can't mix and match types. For example, this is invalid:
func Foo(count int, optional ...string, alsoOptional ...float64) error
If you need something more flexible than this, your best bet is to add a new function, as suggested in #bereal's answer:
func Foo(count int) error { ... }
func FooWithOther(count int, other string) error { ... }
func FooWithMany(count, int, other string, more bool) error { ... }

Related

Is unnamed arguments a thing in Go?

I am writing a parser in Go for Go, and to test it I downloaded a bunch of files from github projects.
In https://github.com/andlabs/ui I bumped into a file containing this piece of code:
func moveLabel(*Button) {
from := movingCurrent
to := 0
if from == 0 {
to = 1
}
movingBoxes[from].Delete(0)
movingBoxes[to].Append(movingLabel, false)
movingCurrent = to
}
It confuse me a bit to see a pointer to a Button without a name as a function argument, which makes it impossible to reference from inside the function.
However, it seems to be syntactically correct given that the compiler doesn't complains.
What is the purpose of unamed functions arguments in Go?
Unnamed parameters are perfectly valid. The Parameter declaration from the spec:
ParameterDecl = [ IdentifierList ] [ "..." ] Type .
As you can see, the IdentifierList (the identifier name or names) is in square brackets, which means it's optional. Only the Type is required.
The reason for this is because the names are not really important for someone calling a method or a function. What matters is the types of the parameters and their order. This is detailed in this answer: Getting method parameter names in Golang
Generally you name variables and parameters so that you can refer to them.
When you don't name something, it's because you don't want to refer to it.
So the question should rather be: Why would I not want to refer to a parameter?
For example because the parameter "is there" (it is passed), but you don't need it, you don't want to use it. Why would it be there if I don't need it?
Because someone or something dictates for specific parameters to be there. For example you want to implement an interface, or you want to pass a function value whose signature is defined by the function type that is expected.
Let's see an example. We have the following MyWriter interface:
type MyWriter interface {
Write(p []byte) error
}
A simplified io.Writer which only returns an error, but does not report the number of bytes written. If you'd want to provide an implementation which just discards the data (similar to ioutil.Discard), then the implementation does not use (does not need to use) its argument:
type DiscardWriter struct{}
func (DiscardWriter) Write([]byte) error { return nil }
And that's all: we don't use the receiver, we don't use the argument. Both can be unnamed. And the implementation does exactly what it should.
Doing so (using unnamed parameters) also documents that the value is not used / referred to.
Another reason can be to provide forward compatibility. If you release a library, you can't change or extend the parameter list without breaking backward compatibility (and in Go there is no function overloading: if you want 2 variants with different parameters, their names must be different too). So you may declare an exported function or method with additional parameters early, but since you don't use them yet, you may leave them unnamed. An example of this is detailed in this answer: Why does Go allow compilation of unused function parameters?
One thing to note here is that you can't mix named and unnamed parameters. If you name some, you must name all. If you don't need all, you may use the blank identifier like in this example:
A simple web server which responds with the "Hello" text to all requests:
http.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
io.WriteString(w, "Hello")
})
panic(http.ListenAndServe(":8080", nil))
The handler function sending back the "Hello" text only uses the response writer w, but not the request structure, so the blank identifier is used as its name.
Another related question:
Why must we declare a variable name when adding a method to a struct in Golang?
Also somewhat related, but regarding using / naming returned values:
Return map like 'ok' in Golang on normal functions
And regarding getting method / function parameter names:
Getting method parameter names in Golang
Unnamed parameters are valid but not referenceable.
They're just for satisfaction of interfaces and signatures.
The purpose of unnamed function arguments is for arguments (which are local variables of the function) which are not referred to in the function's code, and therefore do not need a name. An interesting note about anonymous variables is that they are actually used more commonly than you may think. In Go, a function's return value(s) are usually listed as types, but actually they are also local variables of the function which can be named and manipulated.
See this example in the "Effective Go" page on golang.org
https://golang.org/doc/effective_go.html#named-results
func ReadFull(r Reader, buf []byte) (n int, err error) {
for len(buf) > 0 && err == nil {
var nr int
nr, err = r.Read(buf)
n += nr
buf = buf[nr:]
}
return
}

Golang: how to mock ...interface{} arguents using gomock

I have a Printer interface that uses the standard go Printf function signature:
type Printer interface {
Printf(format string, tokens ...interface{})
}
I would like to be able to mock this interface using gomock, but I'm not sure how setup the tokens ...interface{} argument properly.
I expected that Printf(gomock.Any(), gomock.Any()) would cover all potential cases (since tokens compiles to []interface{}), but it appears you need to setup an explicit call for N number of tokens:
// no tokens
mockPrinter.EXPECT().
Printf(gomock.Any()).
AnyTimes()
// 1 token
mockPrinter.EXPECT().
Printf(gomock.Any(), gomock.Any()).
AnyTimes()
// 2 tokens
mockPrinter.EXPECT().
Printf(gomock.Any(), gomock.Any(), gomock.Any()).
AnyTimes()
// ... up to N tokens
Does anyone know of a better way to do this?
Not possible with the current version of gomock. Maybe you can extend it, and send a pull request in. To understand why it's not possible, you have to look at the mock generated for variadic functions.
To do that, let's look at the examples in gomock's repository, specifically ./sample/mock_user/user.go and ./sample/mock_user/mock_user.go.
Generated Mock
You'll see a function in the Index inteface called Ellip, which is like your Printf function:
type Index interface {
// ...
Ellip(fmt string, args ...interface{})
// ...
}
Now, here's what the mocked function looks like for Ellip:
func (_m *MockIndex) Ellip(_param0 string, _param1 ...interface{}) {
_s := []interface{}{_param0}
for _, _x := range _param1 {
_s = append(_s, _x)
}
_m.ctrl.Call(_m, "Ellip", _s...)
}
Notice anything odd? Well, gomock is creating a slice of interfaces, _s, initialized with the first parameter. Then it appends the variadic parameters to that slice of interfaces, _s.
So, to be clear, it doesn't just append the variadic parameter, _param1, to the slice. Each individual variadic from _param1 is appended to the new slice, by iterating through it.
This means that the slice of variadic parameters is not preserved. It's broken out.
As of October 1, 2017, gomock.Any() works correctly for variadic args: https://github.com/golang/mock/pull/101

How do I wrapper a function with variadic parameters

In Go, it's possible to prefix the final parameter in a function with the ... notation to indicate it is a variadic parameter.
template.ParseFiles is one such function:
func (t *Template) ParseFiles(filenames ...string) (*Template, error)
I am trying to create a function of my own which sets up various common features of my templates and I'd like the calling function to pass in the list of files that need to be parsed but I'm not sure how.
For example if my code looked like this:
type templateMap map[string]*template.Template
func (tmpl templateMap) AddTemplate(name string, files ...string) {
tmpl[name] = template.Must(template.ParseFiles(files)).Delims("{#","#}")
}
I get an error:
cannot use files (type []string) as type string in function argument
How do I wrapper variadic parameters?
To pass a slice in place of the variadic argument of a function, simply suffix it with .... So in your example code, you would instead want:
tmpl[name] = template.Must(template.ParseFiles(files...)).Delims("{#","#}")
Here is a simple example of the concept: http://play.golang.org/p/TpYNxnAM_5

Meaning of ...interface{} (dot dot dot interface)

Below is a piece of Go code I have question about.
Specifically, what is a in this function?
func DPrintf(format string, a ...interface{}) (n int, err error) {
if Debug > 0 {
n, err = fmt.Printf(format, a...)
}
return
}
Could anyone tell me what the three dots are here?
And what does ...interface{} do?
A parameter type prefixed with three dots (...) is called a variadic parameter. That means you can pass any number or arguments into that parameter (just like with fmt.Printf()). The function will receive the list of arguments for the parameter as a slice of the type declared for the parameter ([]interface{} in your case). The Go Specification states:
The final parameter in a function signature may have a type prefixed with .... A function with such a parameter is called variadic and may be invoked with zero or more arguments for that parameter.
A parameter:
a ...interface{}
Is, for the function equivalent to:
a []interface{}
The difference is how you pass the arguments to such a function. It is done either by giving each element of the slice separately, or as a single slice, in which case you will have to suffix the slice-value with the three dots. The following examples will result in the same call:
fmt.Println("First", "Second", "Third")
Will do the same as:
s := []interface{}{"First", "Second", "Third"}
fmt.Println(s...)
This is explained quite well in the Go Specification as well:
Given the function and calls
func Greeting(prefix string, who ...string)
Greeting("nobody")
Greeting("hello:", "Joe", "Anna", "Eileen")
within Greeting, who will have the value nil in the first call, and []string{"Joe", "Anna", "Eileen"} in the second.
If the final argument is assignable to a slice type []T, it may be passed unchanged as the value for a ...T parameter if the argument is followed by .... In this case no new slice is created.
Given the slice s and call
s := []string{"James", "Jasmine"}
Greeting("goodbye:", s...)
within Greeting, who will have the same value as s with the same underlying array.
As far as the interface{} term, it is the empty interface. In other words, the interface implemented by all variables in Go.
This is sort of analogous to java.lang.Object or System.Object in C#, but is instead inclusive of every variable type in the language. So it lets you pass in anything to the method.

Pass string slice to variadic empty interface parameter

A package I am using, gosqlite, has a method with a variadic parameter where its type is the empty interface.
func (s *Stmt) Exec(args ...interface{}) os.Error
I can call this fine if explicitly pass individual parameters:
statement := blah()
error := statement.Exec("hello", 3.0, true) // works fine
However, as the variadic parameter corresponds to placeholders within the in operator of my SQL statement's select, the number of these placeholders is not known at compile time but dynamically changes at run time depending upon what the user is doing. E.g. I end up with SQL akin to the following if the user enters four values:
SELECT * FROM sky WHERE name IN (?,?,?,?)
So naturally I would like to call the Exec method with a slice of strings:
var values []string = getValuesFromUser()
statement := createStatementWithSufficientNumberOfPlaceholders(len(values))
_ := statement.Exec(values...) // compiler doesn't like this
This does not compile. I can get around this problem by creating an empty interface slice and copying the references over:
values2 := make([]interface{}, len(values))
for index, value := range values { values2[index] = value }
_ := statement.Exec(values2...) // compiler happy but I'm not
And this works fine but it feels a bit clunky. I was wondering if there was some trick to be able to pass values directly to this function or, failing that, a neater way of converting the string slice to an empty interface one?
Many thanks.
There is no way to pass a []string directly to a ...interface{} parameter. Doing this requires a linear time copy (with n + 1 allocations!). If the language hid this from you, it would be a significant hidden cost. Normally, passing a slice to a variadic argument just passes the slice into the function.
As for other ways of doing this, you could make it cleaner by writing a function that takes a []string and returns the corresponding []interface{}. Of course, you'll have to write it again for each []T -> []interface{} conversion you want to do, but its a rather short function, and all that changes is the signature. You could use reflection, which comes with an inherent runtime cost, to make the function "generic", such as in:
valuesVal := reflect.ValueOf(values)
...
for i := range values2 { values2[i] = valuesVal.Index(i).Interface() }
I don't have an answer. And I don't suppose there is one since even built-in and variadic copy and append have the same (or compatible concrete) element type "blockhead", but I have two obvious suggestions:
do not return []string from getValuesFromUser() (i.e. pass still unadorned []interface{}),
on the other type end wrap calls to statement.Exec() with a func making []string to []interface{} conversion.
Or on the same, third, obvious note extend type statement with Exec(args ...string).
P.S. I haven't made any benchmarks myself but I don't think this kind of conversion is highly expensive as interface{} feels like a reference type and compiler is probably doing some dirty trickstery behind the curtain... then again perhaps not, though, I'd be happy, too, to learn of an actual solution.
You need to pass a varargs slice of interface{} type like this to the method.
var paramArray []interface{}
paramArray = append(paramArray, "test1")
paramArray = append(paramArray, "test2")
varargsFunc(paramArray...)

Resources