Question

Can Go have optional parameters? Or can I just define two functions with the same name and a different number of arguments?

Was it helpful?

Solution

Go does not have optional parameters nor does it support method overloading:

Method dispatch is simplified if it doesn't need to do type matching as well. Experience with other languages told us that having a variety of methods with the same name but different signatures was occasionally useful but that it could also be confusing and fragile in practice. Matching only by name and requiring consistency in the types was a major simplifying decision in Go's type system.

OTHER TIPS

A nice way to achieve something like optional parameters is to use variadic args. The function actually receives a slice of whatever type you specify.

func foo(params ...int) {
    fmt.Println(len(params))
}

func main() {
    foo()
    foo(1)
    foo(1,2,3)
}

You can use a struct which includes the parameters:

type Params struct {
  a, b, c int
}

func doIt(p Params) int {
  return p.a + p.b + p.c 
}

// you can call it without specifying all parameters
doIt(Params{a: 1, c: 9})

For arbitrary, potentially large number of optional parameters, a nice idiom is to use Functional options.

For your type Foobar, first write only one constructor:

func NewFoobar(options ...func(*Foobar) error) (*Foobar, error){
  fb := &Foobar{}
  // ... (write initializations with default values)...
  for _, op := range options{
    err := op(fb)
    if err != nil {
      return nil, err
    }
  }
  return fb, nil
}

where each option is a function which mutates the Foobar. Then provide convenient ways for your user to use or create standard options, for example :

func OptionReadonlyFlag(fb *Foobar) error {
  fb.mutable = false
  return nil
}

func OptionTemperature(t Celsius) func(*Foobar) error {
  return func(fb *Foobar) error {
    fb.temperature = t
    return nil
  }
}

Playground

For conciseness, you may give a name to the type of the options (Playground) :

type OptionFoobar func(*Foobar) error

If you need mandatory parameters, add them as first arguments of the constructor before the variadic options.

The main benefits of the Functional options idiom are :

  • your API can grow over time without breaking existing code, because the constuctor signature stays the same when new options are needed.
  • it enables the default use case to be its simplest: no arguments at all!
  • it provides fine control over the initialization of complex values.

This technique was coined by Rob Pike and also demonstrated by Dave Cheney.

Neither optional parameters nor function overloading are supported in Go. Go does support a variable number of parameters: Passing arguments to ... parameters

No -- neither. Per the Go for C++ programmers docs,

Go does not support function overloading and does not support user defined operators.

I can't find an equally clear statement that optional parameters are unsupported, but they are not supported either.

You can encapsulate this quite nicely in a func similar to what is below.

package main

import (
        "bufio"
        "fmt"
        "os"
)

func main() {
        fmt.Println(prompt())
}

func prompt(params ...string) string {
        prompt := ": "
        if len(params) > 0 {
                prompt = params[0]
        }
        reader := bufio.NewReader(os.Stdin)
        fmt.Print(prompt)
        text, _ := reader.ReadString('\n')
        return text
}

In this example, the prompt by default has a colon and a space in front of it . . .

: 

. . . however you can override that by supplying a parameter to the prompt function.

prompt("Input here -> ")

This will result in a prompt like below.

Input here ->

I ended up using a combination of a structure of params and variadic args. This way, I didn't have to change the existing interface which was consumed by several services and my service was able to pass additional params as needed. Sample code in golang playground: https://play.golang.org/p/G668FA97Nu

I am a little late, but if you like fluent interface you might design your setters for chained calls like this:

type myType struct {
  s string
  a, b int
}

func New(s string, err *error) *myType {
  if s == "" {
    *err = errors.New(
      "Mandatory argument `s` must not be empty!")
  }
  return &myType{s: s}
}

func (this *myType) setA (a int, err *error) *myType {
  if *err == nil {
    if a == 42 {
      *err = errors.New("42 is not the answer!")
    } else {
      this.a = a
    }
  }
  return this
}

func (this *myType) setB (b int, _ *error) *myType {
  this.b = b
  return this
}

And then call it like this:

func main() {
  var err error = nil
  instance :=
    New("hello", &err).
    setA(1, &err).
    setB(2, &err)

  if err != nil {
    fmt.Println("Failed: ", err)
  } else {
    fmt.Println(instance)
  }
}

This is similar to the Functional options idiom presented on @Ripounet answer and enjoys the same benefits but has some drawbacks:

  1. If an error occurs it will not abort immediately, thus, it would be slightly less efficient if you expect your constructor to report errors often.
  2. You'll have to spend a line declaring an err variable and zeroing it.

There is, however, a possible small advantage, this type of function calls should be easier for the compiler to inline but I am really not a specialist.

Go language does not support method overloading, but you can use variadic args just like optional parameters, also you can use interface{} as parameter but it is not a good choice.

You can pass arbitrary named parameters with a map.

type varArgs map[string]interface{}

func myFunc(args varArgs) {

    arg1 := "default" // optional default value
    if val, ok := args["arg1"]; ok {
        // value override or other action
        arg1 = val.(string) // runtime panic if wrong type
    }

    arg2 := 123 // optional default value
    if val, ok := args["arg2"]; ok {
        // value override or other action
        arg2 = val.(int) // runtime panic if wrong type
    }

    fmt.Println(arg1, arg2)
}

func Test_test() {
    myFunc(varArgs{"arg1": "value", "arg2": 1234})
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top