What is the best way to write a pure function in go if I need to pass a (small) slice in parameter? Slice are not passed by value like array. So it's not possible to guarantee that it will not be modified during the execution of the function. Once solution is to copy the slice every time I call the function. It would work in practice, but I would prefer a more safe solution as there is no way to ensure that a copy will ever be made before the function call.
You are right that since slices are reference values, a truly pure function with a slice argument is not possible.
Depending on your needs, you could use an array. An array has a fixed number of elements and is declared as follows:
var myArray [10]int
Arrays are copied when passed by value.
Another possibility would be to encapsulate the slice in an interface that only allows to read from the slice, not to write to it.
package main
import "fmt"
// The interface
type ReadOnlyStringSlice interface {
Get(int) string
}
// An implementation of ReadOnlyStringSlice
type MyReadOnlySlice struct {
slice []string
}
func (m MyReadOnlySlice) Get(i int) string {
e := m.slice[i]
return e
}
// Your "pure" function
func MyPureFunction(r ReadOnlyStringSlice) {
fmt.Println(r.Get(0))
}
func main() {
m := MyReadOnlySlice{[]string{"foo", "bar"}}
MyPureFunction(m)
}
If you're writing a package, you could export a method which takes a slice but copies it and passes it to the real function:
func MyExportedFunc(someSlice []int) {
sliceCopy := make([]int, len(someSlice))
copy(sliceCopy, someSlice)
myUnexportedFunc(sliceCopy)
}
This, of course, is not a solution for the problem in general, as MyExportedFunc
is not pure. The best way is probably to encapsulate the slice, as @Tom suggested.
Not a real answer, but still worth discussing I suppose.
I think the whole idea is wishful thinking: there's no point in striving to have a pure function in a language which does not in any way use the fact your function is pure. If you could "mark" a function as being pure, Go would in theory be able to somehow use this hint to its advantage (for instance, to reorder execution of some functions in a sequence of calls). Since there's no explicit support for such kind of thing, the function's purity only exists in your mind. For instance, suppose you were able to somehow force a function not to modify a slice passed to it; even then nothing would prevent you from performing another side effect in that function (say, doing I/O or modifying a global variable).
If you're writing a library and want its caller to supply a callback taking a slice which the callback must not change, just state this fact clearly in the documentation.