Optional Parameters in Go?

358,994

Solution 1

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.

Solution 2

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)
}

Solution 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})

Solution 4

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.

Solution 5

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

Share:
358,994
devyn
Author by

devyn

Updated on July 28, 2022

Comments

  • devyn
    devyn over 1 year

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

  • peterSO
    peterSO over 14 years
    "There is no current plan for this [optional parameters]." Ian Lance Taylor, Go language team. groups.google.com/group/golang-nuts/msg/030e63e7e681fd3e
  • jsdw
    jsdw almost 11 years
    It would be great if structs could have default values here; anything the user omits is defaulted to the nil value for that type, which may or may not be a suitable default argument to the function.
  • mk12
    mk12 almost 11 years
    Is make a special case, then? Or is it not even really implemented as a function…
  • nemo
    nemo over 10 years
    @Mk12 make is a language construct and the rules mentioned above don't apply. See this related question.
  • burfl
    burfl about 10 years
    @lytnus, I hate to split hairs, but fields for which values are omitted would default to the 'zero value' for their type; nil is a different animal. Should the type of the omitted field happen to be a pointer, the zero value would be nil.
  • Alix Axel
    Alix Axel about 10 years
    "function actually receives a slice of whatever type you specify" how so?
  • Ferguzz
    Ferguzz about 10 years
    in the above example, params is a slice of ints
  • thiagowfx
    thiagowfx over 9 years
    range is the same case as make, in that sense
  • Deleplace
    Deleplace over 9 years
  • Juan de Parras
    Juan de Parras over 9 years
    But only for the same type of params :(
  • trevorgk
    trevorgk over 9 years
    Method overloads - A great idea in theory and excellent when implemented well. However I have witnessed rubbish indecipherable overloading in practice and would therefore agree with Google's decision
  • maufl
    maufl over 8 years
    @JuandeParras Well, you can still use something like ...interface{} I guess.
  • user3523091
    user3523091 about 8 years
    Clever, but too complicated. The philosophy of Go is to write code in a straightforward way. Just pass a struct and test for default values.
  • user3523091
    user3523091 about 8 years
    With ...type you are not conveying the meaning of the individual options. Use a struct instead. ...type is handy for values that you would otherwise have to put in an array before the call.
  • Petar Donchev
    Petar Donchev over 7 years
    Just FYI, the original author of this idiom, at at least the first publisher referenced, is Commander Rob Pike, whom I consider authoritative enough for Go philosophy. Link - commandcenter.blogspot.bg/2014/01/…. Also search for "Simple is complicated".
  • Motti
    Motti over 6 years
    Cool but you lose type safety (can be called with redundant/missing parameters)
  • UmNyobe
    UmNyobe over 6 years
    this is a builder pattern
  • keymone
    keymone about 6 years
    @burfl yeah, except the notion of "zero value" is absolutely useless for int/float/string types, because those values are meaningful and so you can't tell the difference if the value was omitted from the struct or if zero value was passed intentionally.
  • burfl
    burfl about 6 years
    @keymone, I don't disagree with you. I was merely being pedantic about the statement above that values omitted by the user default to the "nil value for that type", which is incorrect. They default to the zero value, which may or may not be nil, depending on whether the type is a pointer.
  • Tom
    Tom over 5 years
    I'm going to go out on a limb and disagree with this choice. The language designers have basically said, "We need function overloading to design the language we want, so make, range and so on are essentially overloaded, but if you want function overloading to design the API you want, well, that's tough." The fact that some programmers misuse a language feature is not an argument for getting rid of the feature.
  • Jonathan
    Jonathan about 5 years
    No User defined operators is a terrible decision, as it is the core behind any slick math library, such as dot products or cross products for linear algebra, often used in 3D graphics.
  • MikeSchinkel
    MikeSchinkel about 5 years
    #JMTCW, but I find this approach very difficult to reason about. I would far prefer to pass in a struct of values, whose properties could be func()s if need be, than that bend my brain around this approach. Whenever I have to use this approach, such as with the Echo library, I find my brain getting caught in the rabbit hole of abstractions. #fwiw
  • Brent Bradburn
    Brent Bradburn over 4 years
    Here's some commentary on this approach: reddit.com/r/golang/comments/546g4z/…
  • Brent Bradburn
    Brent Bradburn over 4 years
  • NotX
    NotX over 4 years
    @Tom same with Generics. Makes you feel a bit as a second-class developer.
  • Tom
    Tom over 4 years
    @NotX - yes. The discussions on generics in Go all boil down to the compiler developers saying, "Just because every other sane language developed in the last twenty years has generic types doesn't mean we have to admit that generic types are logically, physically, philosophically or ethically possible."
  • Marcello Romani
    Marcello Romani over 4 years
    I need to vent my outrage here - pointless but useful for my own sanity. The fact that method overloading and optional parameters can and have been misused to produce unreadable mess is not a valid reason to not implement them.
  • Zain Rizvi
    Zain Rizvi over 4 years
    @Tom they consider function overloading abusive but goto's are just fine... (╯°□°)╯︵ ┻━┻
  • Cyberience
    Cyberience about 4 years
    whats wrong with using ...interface{} ? Since this can accept parameters of various types and you just check the types within your function, then it can be overloaded... Like this: func myLog(msg ...interface{}) { do somthing }
  • ghd
    ghd about 4 years
    @Tom In the case of make, range and others, the documentation of Go is clear and the idiom can be mastered in a reasonable amount of time. The language designers have decided to use a controlled form of function overloading in this case such that everybody's aware of the mechanics. The same cannot be said of the users of the language. There's effort required from the API developer to develop the API and then document the API clearly. And, then there's effort required from the users of the API to be aware of the various overloaded versions of the API to be able to effectively use it.
  • Tom
    Tom about 4 years
    @ghd So, basically, because some developers will do this badly, the language designers say that they're the only ones allowed to do it. Which is what I said.
  • Tom
    Tom about 4 years
    @Cyberience Seriously? What's wrong with it is that you're giving up compile-time type checking (are you sure the right type is being passed as interface{}? every single time that function is called?) and have to write reams of boilerplate code to implement it.
  • Cyberience
    Cyberience about 4 years
    @Tom I think the point was How could it be done, rather than the merits of right or wrong. True, it can be cumbersome, but in some cases, you may have a situation where say you have incoming json and variable format to handle. I come from pascal back ground where everything is pretty tight, and agree overloading can introduce problems to solve. but hey, as Programmers, is that not our job? To Create Problems to Solve and stand proud after solving?
  • Tom
    Tom about 4 years
    @Cyberience Perhaps. But there are good solutions and bad solutions, and languages that force bad solutions on us should be considered pathological. Passing interface{} as a type is not a long way advanced from passing void* in C and is nearly as bad an idea.
  • Cyberience
    Cyberience about 4 years
    @Tom true, but since programming is an art form, you could suggest that this is a bad idea, but here goes.
  • Yash Kumar Verma
    Yash Kumar Verma about 4 years
    this made me feel that a perfect language doesn't exist. loved everything about go, but this :(
  • r---------k
    r---------k almost 4 years
    thanks, was looking for this idiom. Could as well be up there as the accepted answer.
  • Dewan Ahmed
    Dewan Ahmed almost 4 years
    @Tom, for GoLang, "simplicity" is a feature (and a pretty important one) so getting rid of a rarely used feature that creates complexity; makes good sense to many.
  • Tom
    Tom almost 4 years
    @DewanAhmed - Not sure I see passing ...interface{} as simpler than strongly-typed optional arguments. It's simpler for the compiler implementer, sure, but for people using the language, it leads to an ugly mess of length checks and type assertions at the top of the function. AFAICT making life simpler for the compiler implementer at the expense of ugly, error-prone boilerplate for the user is never a language feature, always a defect.
  • Ярослав Рахматуллин
    Ярослав Рахматуллин over 3 years
    +2 Clever, but complicated. I'm trying to think of a case where I would want to do this. I think only if I'm doing support for some commercial API that people pay to use, and doing this would reduce the number of questions I receive every day. Otherwise... fuck no, too much boilerplate. Nice idea tho, strikes me as somewhat similar to the "builder pattern" from Fowler's "Effective Java". This gets a vote up for increasing the write-only factor of the code :)
  • Ярослав Рахматуллин
    Ярослав Рахматуллин over 3 years
    Meh. What happens if A produces an error, but not B, C, D, and you don't care about A?
  • Brent Bradburn
    Brent Bradburn over 3 years
    @ЯрославРахматуллин: It's a tutorial, not live code. Sometimes it's nice if things are explained.
  • pcting
    pcting over 3 years
    this feels like a simplified form of the magnet pattern: clianz.com/2016/04/26/scala-magnet-pattern
  • Benehiko
    Benehiko over 3 years
    this is such an amazing answer! Thanks a lot :)
  • Dulara Malindu
    Dulara Malindu over 3 years
    That will limit the IDE support. and we will not be able to use a different kind of parameter mix. but writing two separate functions is also cumbersome.
  • NotX
    NotX about 3 years
    The longer I work with Go, the less do I see the simplicity it's advertising. It's not just the lack of many features which could reduce the verbosity and therefore could increase the readability, but also issues like highly unreliable nil-checks and the frequent need of reflections for information which you would expect to be available out of the box, especially if you've got to work with interface{} or pointers. I mean, just check how you're supposed to read data from a sql.Row... and that's just the tip of the iceberg.
  • Sami Fouad
    Sami Fouad about 3 years
    IMO I largely agree with Tom here. The way Swift handles parameters is MINT and I love it with a passion and I wish everyone just did it that way, but especially Go. being able to have a different name entirely for function callers is brilliant. It makes code readability infinitely better. Optionals. Default values. Tuples. Optional tuples. But I'm over here dealing with this nonsense because I love simplicity and goroutines. lol. Tradeoffs are hard, but do they have to be this hard??
  • Eric L.
    Eric L. almost 3 years
    This has a way of saying "go ahead and pass me a function to call" and could well do anything you like as long as it doesn't crash :) really love the pattern Idea! (but yes, it's clearly for commercial and/or flexible libraries for users).
  • VinGarcia
    VinGarcia over 2 years
    @ЯрославРахматуллин you could just separate the calls, e.g. build everything you care about first, then check the errors then set what you don't care to check. Or if you are the one writing the constructor in the first place you can just ignore the errors internally and not receive a *error for setting A.
  • Michael Yohanes
    Michael Yohanes over 2 years
    Totally agree.Sometimes putting nil as parameter can be much simpler than additional changes.
  • Darwayne
    Darwayne over 2 years
    I’m a huge fan of this pattern and have created a code gen tool to simplify usage of this pattern: github.com/darwayne/builder-gen
  • theist
    theist over 2 years
    I like this over the other alternatives. Also this is a pattern I've seen across many libraries, when something has different options and is going to be reusable you can create a struct to represent those options and pass the options by parameter, or you can nil the options to use defaults. Also the options can be documented in their own struct and you can create predefine sets of options. I've seen this in GitHub client library and go-cache library among others.
  • Alan Carlyle
    Alan Carlyle over 2 years
    Was looking to see if optional parameters or alternatively parameter default values could be done so this is possible; func (n *Note) save(extension string = ".txt") { ... } making ".txt" the default yet changeable extension of a file. Yet now am getting the idea this is just not the philosophy behind go and should just use separate Save() and SaveWithExtension(ext string) functions. Better to not fight it, doing so will just make everything harder in the long run.
  • Alan Carlyle
    Alan Carlyle over 2 years
    I keep hearing mention of how optional/default parameters and overloading is not included as it can lead to messy coding. Then why does Go have a goto? The argument that sometimes goto can make code similar and easier to read does not wash given optional/default parameters and overloading can sometimes also improve rather than detract from code quality.
  • Alan Carlyle
    Alan Carlyle over 2 years
    I feel that the fact that an option such as this needs to be considered and can be used highlights that it might be better to have optional and default parameters. At least if we have them then the purpose is clear instead of being concealed behind artificial constructs that obscure what developers intention is and which could themselves end up being misused beyond what they are intended for.
  • Adonis
    Adonis over 2 years
    Until you start using iota and "auto incremented" constants, in which case good luck with unadressable constants (because of course constants are magic and don't have a memory address)
  • Maxs728
    Maxs728 about 2 years
    @madzohan please don't change my code example to fit your needs... you can request that the changes are made or provide your own sample below... Your example fundamentally changed the functionality of my example. A void function that does something does not need a return to suite your needs.
  • glycoslave
    glycoslave almost 2 years
    ugh, that is horrible.
  • Daniel
    Daniel almost 2 years
    this is not the point of the question, the problem still remains as you still need to call function with nil/default structure as second parameter.