Can Go have optional parameters? Or can I just define two different functions with the same name and a different number of arguments?
-
1Related: this is how it can be done to enforce mandatory parameters when using variadic as the optional parameters: [Is it possible to trigger compile time error with custom library in golang?](http://stackoverflow.com/questions/37270743/is-it-possible-to-trigger-compile-time-error-with-custom-library-in-golang) – icza Aug 29 '16 at 10:46
-
85Google made a terrible decision, because sometimes a function has a 90% use case and then a 10% use case. The optional arg is for that 10% use case. Sane defaults means less code, less code means more maintainability. – Jonathan Mar 17 '19 at 01:15
-
6I think not having optional parameters is a good decision. I've seen optional parameters abused pretty severely in C++ -- 40+ arguments. It's very error-prone to count through the arguments and make sure you're specifying the right one, especially without named parameters. Much better to use a struct as mentioned by @deamon . – jnnnnn May 25 '21 at 07:05
-
5@Jonathan there are several ways to deal with this. One way is to pass a struct with all parameters for the function. This will have the added benefit of having named parameters (clearer than positional parameters) and all parameters which are not provided have their default value. And of course just creating a wrapper function, which passes the default value to the full function. e.g. Query and QueryWithContext – Falco Aug 05 '21 at 13:06
-
2@Falco modern IDEs auto-generate named parameters from semantics, so making the programmer rearchitect their code to do something an IDE can do for you seems non-ideal – Jonathan Aug 17 '21 at 18:45
-
@Jonathan most IDEs don't display parameter names when casually reading over code. One usually has to select the function call to see the signature and then order the actual parameters to the list of parameter-names in your head. Most code styles / clean code papers also discourage long parameter lists in functions. One should either pass a struct or use an object oriented design when dealing with a function needing a lot of parameters. – Falco Aug 17 '21 at 19:00
-
1@Falco I specifically stated *modern* IDEs. Most legacy IDEs have the behavior you mentioned. – Jonathan Aug 25 '21 at 00:54
-
2@Jonathan it doesn't seem to work out of the box in VS Code, Visual Studio, IntelliJ, atom or sublime. What IDE are you referring to, or are there extensions/settings which provide this ? – Falco Aug 26 '21 at 09:38
15 Answers
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.

- 344,730
- 71
- 640
- 635
-
86Is `make` a special case, then? Or is it not even really implemented as a function… – mk12 Jul 12 '13 at 02:08
-
91@Mk12 `make` is a language construct and the rules mentioned above don't apply. See [this related question](http://stackoverflow.com/q/18512781/1643939). – nemo Oct 26 '13 at 23:11
-
9
-
25Method 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 – trevorgk Nov 30 '14 at 14:38
-
333I'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. – Tom Oct 24 '18 at 08:06
-
8@Tom same with Generics. Makes you feel a bit as a second-class developer. – NotX Sep 29 '19 at 09:57
-
8@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." – Tom Sep 29 '19 at 10:41
-
18I 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. – Marcello Romani Oct 01 '19 at 09:26
-
1whats 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 } – Cyberience Mar 09 '20 at 09:19
-
@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. – ghd Apr 04 '20 at 14:01
-
1@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 Apr 06 '20 at 14:02
-
6@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. – Tom Apr 06 '20 at 14:04
-
@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? – Cyberience Apr 08 '20 at 08:19
-
3@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. – Tom Apr 08 '20 at 15:30
-
@Tom true, but since programming is an art form, you could suggest that this is a bad idea, but here goes. – Cyberience Apr 15 '20 at 07:46
-
2@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. – Dewan Ahmed Jul 21 '20 at 05:20
-
3@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. – Tom Jul 22 '20 at 09:36
-
2The 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. – NotX Mar 26 '21 at 21:43
-
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?? – Sami Fouad Apr 07 '21 at 04:17
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)
}

- 5,777
- 7
- 34
- 41
-
"function actually receives a slice of whatever type you specify" how so? – Alix Axel Feb 12 '14 at 19:23
-
8
-
128
-
26@JuandeParras Well, you can still use something like ...interface{} I guess. – maufl Sep 09 '15 at 12:42
-
11With ...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. – user3523091 Jan 30 '16 at 23:36
-
1Cool but you lose type safety (can be called with redundant/missing parameters) – Motti Jan 07 '18 at 12:11
-
11this made me feel that a perfect language doesn't exist. loved everything about go, but this :( – Yash Kumar Verma Apr 17 '20 at 20:33
-
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. – Dulara Malindu Dec 30 '20 at 11:29
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})
The main advantage over an ellipsis (params ...SomeType
) is that you can use the param struct with different parameter types.

- 89,107
- 111
- 320
- 448
-
17It 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. – jsdw Jul 06 '13 at 13:28
-
55@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. – burfl Feb 11 '14 at 15:23
-
10@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. – keymone Mar 28 '18 at 10:41
-
3@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. – burfl Mar 29 '18 at 11:32
-
6I 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. – Alan Carlyle Nov 27 '21 at 10:19
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
}
}
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.

- 7,243
- 6
- 49
- 61

- 6,812
- 5
- 28
- 41
-
8Sources : http://commandcenter.blogspot.com.au/2014/01/self-referential-functions-and-design.html , http://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis – Deleplace Nov 09 '14 at 16:17
-
37Clever, 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 Jan 30 '16 at 23:23
-
21Just 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 - https://commandcenter.blogspot.bg/2014/01/self-referential-functions-and-design.html. Also search for "Simple is complicated". – Petar Donchev Oct 31 '16 at 16:11
-
Upvoted long ago, but you write: _provide convenient ways for your user to use or **create** standard options._ If `FooBar` is an opaque struct type, I don't see how users could create additional options. If `FooBar` isn't opaque, then the benefits of functional options is moot, because users now have two ways of initialising a `FooBar`: via a struct literal or via the factory function ("constructor"). My conclusion is that optional options work best when the set of options is meant to be closed and controlled by the package author. – jub0bs Oct 24 '22 at 11:26
-
@user3523091 [Simplicity is complicated](https://www.youtube.com/watch?v=rFejpH_tAHM). – jub0bs Oct 24 '22 at 11:54
-
@jub0bs for an opaque `Foobar` type, the library user can create an option by calling `OptionTemperature` e.g. `opt := OptionTemperature(27)` – Deleplace Oct 25 '22 at 14:31
-
@Deleplace Perhaps I don't understand what you meant by "create". Users can use an existing option thanks to the exported factory functions, yes; however, if `FooBar` is opaque, users cannot _create_ a new `OptionFooBar` value that does anything useful. – jub0bs Oct 25 '22 at 14:38
-
@user3523091 the problem with go is that, in the process of making the language specification itself simple, they made it borderline impossible for those developing in it to keep the *code* simple. "Test for default values" only works if the relevant type has a default value that isn't itself meaningful. – Swagner Jan 27 '23 at 02:41
Neither optional parameters nor function overloading are supported in Go. Go does support a variable number of parameters: Passing arguments to ... parameters

- 158,998
- 31
- 281
- 276
You can pass arbitrary named parameters with a map. You will have to assert types with "aType = map[key].(*foo.type)
" if the parameters have non-uniform types.
type varArgs map[string]interface{}
func myFunc(args varArgs) {
arg1 := "default"
if val, ok := args["arg1"]; ok {
arg1 = val.(string)
}
arg2 := 123
if val, ok := args["arg2"]; ok {
arg2 = val.(int)
}
fmt.Println(arg1, arg2)
}
func Test_test() {
myFunc(varArgs{"arg1": "value", "arg2": 1234})
}

- 7,599
- 1
- 41
- 60

- 51,587
- 17
- 154
- 173
-
1Here's some commentary on this approach: https://www.reddit.com/r/golang/comments/546g4z/namedoptional_function_parameters/ – Brent Bradburn Aug 01 '19 at 13:25
-
1Follow the link at [Does the Go language have function/method overloading?](https://stackoverflow.com/a/6987002/86967) – Brent Bradburn Sep 11 '19 at 14:26
-
1@ЯрославРахматуллин: It's a tutorial, not live code. Sometimes it's nice if things are explained. – Brent Bradburn Sep 05 '20 at 23:59
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.

- 730,956
- 141
- 904
- 1,278

- 854,459
- 170
- 1,222
- 1,395
-
9"There is no current plan for this [optional parameters]." Ian Lance Taylor, Go language team. http://groups.google.com/group/golang-nuts/msg/030e63e7e681fd3e – peterSO Jan 09 '10 at 17:25
-
1No 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. – Jonathan Mar 17 '19 at 01:09
So I feel like I'm way late to this party but I was searching to see if there was a better way to do this than what I already do. This kinda solves what you were trying to do while also giving the concept of an optional argument.
package main
import "fmt"
type FooOpts struct {
// optional arguments
Value string
}
func NewFoo(mandatory string) {
NewFooWithOpts(mandatory, &FooOpts{})
}
func NewFooWithOpts(mandatory string, opts *FooOpts) {
if (&opts) != nil {
fmt.Println("Hello " + opts.Value)
} else {
fmt.Println("Hello")
}
}
func main() {
NewFoo("make it work please")
NewFooWithOpts("Make it work please", &FooOpts{Value: " World"})
}
Update 1:
Added a functional example to show functionality versus the sample

- 591
- 2
- 8
- 18
-
2I 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. – theist Oct 30 '21 at 11:22
-
1@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. – Maxs728 Jan 31 '22 at 19:24
Go doesn’t support optional parameters , default values and function overloading but you can use some tricks to implement the same.
Sharing one example where you can have different number and type of arguments in one function. It’s a plain code for easy understanding you need to add error handling and some logic.
func student(StudentDetails ...interface{}) (name string, age int, area string) {
age = 10 //Here Age and area are optional params set to default values
area = "HillView Singapore"
for index, val := range StudentDetails {
switch index {
case 0: //the first mandatory param
name, _ = val.(string)
case 1: // age is optional param
age, _ = val.(int)
case 2: //area is optional param
area, _ = val.(string)
}
}
return
}
func main() {
fmt.Println(student("Aayansh"))
fmt.Println(student("Aayansh", 11))
fmt.Println(student("Aayansh", 15, "Bukit Gombak, Singapore"))
}

- 19,179
- 10
- 84
- 156

- 2,687
- 24
- 24
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 ->

- 3,272
- 1
- 25
- 28
You could use pointers and leave them nil if you don't want to use them:
func getPosts(limit *int) {
if optParam != nil {
// fetch posts with limit
} else {
// fetch all posts
}
}
func main() {
// get Posts, limit by 2
limit := 2
getPosts(&limit)
// get all posts
getPosts(nil)
}

- 621
- 1
- 7
- 11
-
1Totally agree.Sometimes putting nil as parameter can be much simpler than additional changes. – Michael Yohanes Aug 20 '21 at 05:59
-
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 Nov 15 '21 at 13:53
-
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) – Adonis Jan 21 '22 at 14:36
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.

- 71
- 2
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:
- 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.
- 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.

- 1,015
- 12
- 19
-
1
-
Meh. What happens if A produces an error, but not B, C, D, and you don't care about A? – Ярослав Рахматуллин Sep 05 '20 at 20:57
-
@ЯрославРахматуллин 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. – VinGarcia Aug 04 '21 at 13:56
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

- 71
- 1
- 4
Another possibility would be to use a struct which with a field to indicate whether its valid. The null types from sql such as NullString are convenient. Its nice to not have to define your own type, but in case you need a custom data type you can always follow the same pattern. I think the optional-ness is clear from the function definition and there is minimal extra code or effort.
As an example:
func Foo(bar string, baz sql.NullString){
if !baz.Valid {
baz.String = "defaultValue"
}
// the rest of the implementation
}

- 2,431
- 1
- 24
- 34
-
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. – Daniel Jul 08 '22 at 08:22