function's argument default value

1,586 views
Skip to first unread message

Masoud Ghorbani

unread,
Aug 22, 2018, 12:39:37 PM8/22/18
to golang-nuts
Why there isn't function argument default value in Golang explicitly like Typescript and Python?

Jan Mercl

unread,
Aug 22, 2018, 12:48:34 PM8/22/18
to Masoud Ghorbani, golang-nuts
On Wed, Aug 22, 2018 at 2:39 PM Masoud Ghorbani <msud.g...@gmail.com> wrote:

> Why there isn't function argument default value in Golang explicitly like Typescript and Python? 

What are the possible benefits? The only things that come to my mind are IMO negative. The definition of the default value is in a different place than the call site is. It can be in a different file or even in a different package. Go supports even binary-only packages, so the definition is possible not available in source form at all.

tl;dr:

        foo(42)

says everything to know what the value passed to foo is.

        foo()

does not and one has to lookup the definition of foo to see if foo has zero parameters or one default parameter and then check what the default value is.

--

-j

Masoud Ghorbani

unread,
Aug 22, 2018, 1:20:14 PM8/22/18
to golang-nuts
In my description, I used the argument title instead parameter, sorry for this confusion. 

Jan Mercl

unread,
Aug 22, 2018, 1:26:55 PM8/22/18
to Masoud Ghorbani, golang-nuts
On Wed, Aug 22, 2018 at 3:20 PM Masoud Ghorbani <msud.g...@gmail.com> wrote:

> In my description, I used the argument title instead parameter, sorry for this confusion. 

Now I'm lost in translation ;-) Can you please show some code illustrating the topic? Like code written now vs code written while feature X would be present?


--

-j

Masoud Ghorbani

unread,
Aug 22, 2018, 1:43:59 PM8/22/18
to golang-nuts
:)) ok let me show you in the following example:

def sayHey(name="You"):
   
print('Hey, {0}'.format(name))

sayHey
() # Hey, You
sayHey
('John') # Hey, John

but we don't have parameters default value like Python in Golang. if I want to do this action simply without using structs I should write the below dumb lines:

func sayHey(name string) string {
   
if name == "" {
        name
= "You"
   
}

    fmt
.Sprintf("Hey, %s", name)
}


Marvin Stenger

unread,
Aug 22, 2018, 2:58:20 PM8/22/18
to golang-nuts
The semantically equivalent would be variadic arguments:

func sayHey(args ...string) string {
    name
:= "You"
   
if len(args) > 0 {
        name
= args[0]
   
}
   
return fmt.Sprintf("Hey, %s", name)
}



But I would advise you not to use it for the purpose of default arguments.

Marvin Stenger

unread,
Aug 22, 2018, 3:09:15 PM8/22/18
to golang-nuts
Am Mittwoch, 22. August 2018 15:43:59 UTC+2 schrieb Masoud Ghorbani:
:)) ok let me show you in the following example:

def sayHey(name="You"):
   
print('Hey, {0}'.format(name))

sayHey
() # Hey, You
sayHey
('John') # Hey, John


Btw  Python3.6 also features f-strings:

def sayHey(name="You"):
   
print(f'Hey, {name}')


Wojciech S. Czarnecki

unread,
Aug 22, 2018, 5:20:03 PM8/22/18
to golan...@googlegroups.com
On Wed, 22 Aug 2018 08:09:14 -0700 (PDT)
Marvin Stenger <marvin.s...@gmail.com> wrote:

> <https://docs.python.org/3/reference/lexical_analysis.html#f-strings>:

A pony. Seven-legged, with three tails, lacking head.
(Excuse me, list, just could not resist.)

@Marvin:
Go uses the default of zero. What you proposed would be against sacred
readability of Go code. See Jan Mercl's reply for details.

PS. Try [https://racket-lang.org/].
They allow every one to write code readable only by the very same person. ;)

--
Wojciech S. Czarnecki
<< ^oo^ >> OHIR-RIPE

Louki Sumirniy

unread,
Aug 23, 2018, 12:08:23 AM8/23/18
to golang-nuts
There is a default value for everything in Go. Null. 0, "" and nil. As someone else said, if you want a parameter to be optional you probably need ...interface{} and then infer no parameter as 'use the default'. Going a little further, you can build default values into a constructor function for an interfaced type. 

Oh, probably the neatest solution is to make a struct that lets you input the parameters either in-order or with labels instead. Then you can use &TypeName{} to mean 'use defaults' or whichever parameters are not specified get automatically set to default, either unlabeled and ordered such that the values that will be asserted to defaults are not the first ones in a struct literal used to feed parameters in. Or make the names nice and concise so they aren't troublesome to add (and if your code is going to often use defaults, probably you won't even have to specify many values very often anyway).

Assertions and labeled parameters are nice features but they don't really save you that much time. I would suggest that it's more likely you need to rethink the structure of your application and make slightly different named parameters for those calls that will use defaults for specific parameters.

Another thing is that you can make null variables imply the use of defaults, then you only need to put 'nil' '""' or '0' into these parameters and the code will test and fill them automatically. Or if null isn't handy, you can define sentinel values for a type that indicate 'use defaults'.

Masoud Ghorbani

unread,
Aug 23, 2018, 7:44:17 AM8/23/18
to golang-nuts
Your opinion is like to say all of the python application should rethink and re-write their structure because they used default values. I think having default values for parameters is just a feature which will make codebase readable and smaller than before.

Louki Sumirniy

unread,
Aug 23, 2018, 8:32:26 AM8/23/18
to golang-nuts
Actually, my real opinion is that I like these default argument values, I also like concise asserts at the head of functions that automatically sanitise data. But they cost quite a lot which is likely why Go doesn't have them. Default arguments are the least useful of the two, asserts have a much greater effect on correctness which is why many functional languages let you set such conditions in a function.

Louki Sumirniy

unread,
Aug 23, 2018, 8:36:49 AM8/23/18
to golang-nuts
Actually, going a little further, I would like to see a change in Golang where parameter and return tuples can be set the same way as structs - so if you use named labels ( label="value ) it assumes null for any others specified. Then you can add one more feature, which is also related and gives you what you want - that you can specify defaults inside the parameter block in a function header for values when you want something other than null values when unspecified using labels.


On Thursday, 23 August 2018 09:44:17 UTC+2, Masoud Ghorbani wrote:

Ian Lance Taylor

unread,
Aug 23, 2018, 8:41:12 PM8/23/18
to Masoud Ghorbani, golang-nuts
On Thu, Aug 23, 2018 at 12:44 AM, Masoud Ghorbani
<msud.g...@gmail.com> wrote:
>
> Your opinion is like to say all of the python application should rethink and
> re-write their structure because they used default values. I think having
> default values for parameters is just a feature which will make codebase
> readable and smaller than before.

Default values for parameters is in effect a simple form of function
overloading. If F(int) has a default value for the parameter, then
you've overloaded F with another function F() that takes no arguments.
Go doesn't have function overloading in general, and it doesn't have
default parameter values either.

Ian

Axel Wagner

unread,
Aug 23, 2018, 8:53:32 PM8/23/18
to msud.g...@gmail.com, golang-nuts
On Thu, Aug 23, 2018 at 9:44 AM Masoud Ghorbani <msud.g...@gmail.com> wrote:
Your opinion is like to say all of the python application should rethink and re-write their structure because they used default values.

One general thing to observe in all these discussions is, that Go is not Python (or Rust, Haskell, C#,…). Different languages have different goals, weigh them differently and choose different solutions to get there - and that's okay. Saying something isn't right for Go isn't the same as saying something isn't right for a different language. In the same way, saying some other language is doing something is not a convincing argument that Go should do it too.
 
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Masoud Ghorbani

unread,
Aug 23, 2018, 11:20:17 PM8/23/18
to golang-nuts
I didn't get the relation of function overloading with parameters default value. actually, function overloading means define functions with similar names.

Ian Lance Taylor

unread,
Aug 23, 2018, 11:26:36 PM8/23/18
to Masoud Ghorbani, golang-nuts
On Thu, Aug 23, 2018 at 4:20 PM, Masoud Ghorbani
<msud.g...@gmail.com> wrote:
> I didn't get the relation of function overloading with parameters default
> value. actually, function overloading means define functions with similar
> names.

Right. After adding a default value for the parameter, you have two
functions with similar names:
F(int)
F()

It's exactly as though you overloaded F.

Ian


> On Friday, August 24, 2018 at 1:11:12 AM UTC+4:30, Ian Lance Taylor wrote:
>>
>> On Thu, Aug 23, 2018 at 12:44 AM, Masoud Ghorbani
>> <msud.g...@gmail.com> wrote:
>> >
>> > Your opinion is like to say all of the python application should rethink
>> > and
>> > re-write their structure because they used default values. I think
>> > having
>> > default values for parameters is just a feature which will make codebase
>> > readable and smaller than before.
>>
>> Default values for parameters is in effect a simple form of function
>> overloading. If F(int) has a default value for the parameter, then
>> you've overloaded F with another function F() that takes no arguments.
>> Go doesn't have function overloading in general, and it doesn't have
>> default parameter values either.
>>
>> Ian
>

Masoud Ghorbani

unread,
Aug 23, 2018, 11:38:36 PM8/23/18
to golang-nuts
You're right but I think developers of Go can think about that because its benefits are obvious.

andrey mirtchovski

unread,
Aug 24, 2018, 12:51:37 AM8/24/18
to msud.g...@gmail.com, golang-nuts
> You're right but I think developers of Go can think about that because its benefits are obvious.

can you please enumerate those benefits? many gophers are not
convinced they are obvious.

Louki Sumirniy

unread,
Aug 24, 2018, 1:59:58 AM8/24/18
to golang-nuts
I have to agree. The idiomatic solution would be defining multiple functions that wrap around another, and it is not onerously boilerplatey. As Ian says, default values do constitute effectively function overloads.

There is  reason why function overloading is not available in Go. Just go look at some typical c++ code. Not only overloading but operator overloading as well. Looking at one source file you may not be able to figure out what any symbol in the file actually refers to. Watch the way symbol analysis tools like Codelens give you references to a given symbol... I know in the bitcoin codebase, nearly every symbol in the whole damn codebase codelens suggests like 5 different definitions for everything. One of them is correct, of course, but the only way to find out is to compile it, and an eternity later it just does stuff and because the source code is so difficult to analyse, you are still none the wiser.

I would think that for those who really really need such  feature, the solution would be with using a code generator/preprocessor. But then you will lose a lot of the advantage of writing it in Go in the first place.

Louki Sumirniy

unread,
Aug 24, 2018, 2:04:53 AM8/24/18
to golang-nuts
I don't think the benefits are obvious and being able to leave out parameters by specifying one by name is of dubious benefit. Could you not simply write a short set of if statements that insert a default by using a nulled sentinel. Like this:

func PrintMessage(s string) {
  if s == "" {
    s = "default value"
  }
  DoSomeThing(s)
}

Then call it

PrintMessage("")

Masoud Ghorbani

unread,
Aug 24, 2018, 12:26:48 PM8/24/18
to golang-nuts
I found this talks which Rob Pike at syntax section explained why they omitted default function arguments.
Thanks all about this discussion.

Louki Sumirniy

unread,
Aug 24, 2018, 12:47:21 PM8/24/18
to golang-nuts
This is in the next section but it's probably even more important:

There is one more aspect of naming to be mentioned: method lookup is always by name only, not by signature (type) of the method. In other words, a single type can never have two methods with the same name. Given a method x.M, there's only ever one M associated with x. Again, this makes it easy to identify which method is referred to given only the name. It also makes the implementation of method invocation simple.

The previous section does explain why this decision was made, it makes it far simpler to write tools to manipulate or analyse the code. One name = only one variable, never any ambiguity to resolve, and this applies also to the human reading it. 

In go you can make functions that accept a slice of interface{}, and in theory you could use this with a switch and either strings or predefined constants (with iota) to create functions that you can interpret any set of parameters with the caveat that a parameter must always be passed to identify each bit of data so you can type assert it.

Louki Sumirniy

unread,
Aug 24, 2018, 1:05:33 PM8/24/18
to golang-nuts
I should just add one more thing, something I discovered when I saw the cete wrapper for the dgraph's badger KV store: https://github.com/1lann/cete

If you design your interfaces carefully, and make it so that any function that does not by necessity return some other type, passes through the pointer receiver to the caller. These functions can be strung together in long chains, here is an example from a test on one type I have made that uses this design pattern:

  fmt.Println(*NewLockedBuffer().FromRandomBytes(23).FromBytes(NewBytes().FromString(A)).ToBytes().ToString())

By designing it so that type conversions can pass through an intermediate type you can push data into and out of your variables, and most importantly, if you make a constructor ( NewLockedBuffer() ) and then you can write a single function that loads a specific member of the struct, and thus for an object with multiple values, it is functionally equivalent to the 'default parameter unless specified' model that you get with named parameters like in Python and other similar languages. Except it's far clearer and reads very well for a human.

One caveat to this design pattern I have noticed, however, because I am writing code working with the memguard library, is that you probably should be very specific in each of the functions whether it copies, references or relocates data from one structure to another. A lack of clarity about this could cause all kinds of nasty side effects and complex, hard to solve bugs.

Robert Johnstone

unread,
Aug 24, 2018, 1:15:28 PM8/24/18
to golang-nuts
Hello,

This is misleading.  With default arguments, there remains only one function definition, which makes it quite different from function overloading where there would be multiple definitions.  Default parameters provides syntax sugar at the call site, but does not create additional functions.

I'm not arguing for default parameters.  The explanation in https://talks.golang.org/2012/splash.article#TOC_10 is good, given Go's philosophy.  

Robert

Louki Sumirniy

unread,
Aug 24, 2018, 2:59:15 PM8/24/18
to golang-nuts
The distinction you are missing is that Go only considers the name of an interface method to be unique, meaning only one parameter definition is allowed per name. What this means is that in Go these have to be separate functions and by definition, differently named. This is why I am suggesting that a method of structuring complex objects that is used extensively in the standard library is the solution -

  • you create a function with some set of defaults and no parameter
  • then appropriately named functions
  • and all functions that return no specific other values return the pointer to the receiver
Then you can have the same result as only needing to specify parameters that differ from defaults, but with the aditional benefit you can create multiple configurations for initialisation, loading, copying and transferring in from other types especially if they are same as members or commutable to members of the receiver type.

Michael Jones

unread,
Aug 24, 2018, 4:23:26 PM8/24/18
to Louki Sumirniy, golang-nuts
Reinforcing comments above: defaults are not missing, they have been avoided. One can argue default arguments are either a mistake in API design or neglect in code refactoring. 

On the mistake side, the argument is that making "cook(n)" mean "make pizza if n is missing or cook n if otherwise" adds complexity of comprehension in exchange for simplicity of expression. Use of varadic arguments does not change this view that the savings are a deferred cost. As a program user, extender, debugger, or reviewer, the idea is that you would rather see cookPizza() and cook(food) in the code, and of course, cookPizza() would just be cook("pizza"), the inliner would do this in compilation, and the effect would be as if a default, but the code would be more plain, more descriptive, and less surprising.

As for refactoring, one need not look far to find an existing C++ API to which has been added some last-minute parameter, defined as nil or default, but which allows invisible insertion of new functionality not previously provided. That is so seductive that most of us have done it. Unfortunately, it also means that all the old call sites have a hidden secret not visible to those who read the code. This has proven to be a source of woe. Better is to refactor the API to best express the new truth and feature set.

These are not "get it to work by yourself" concerns, they are "keep it working and use it across teams" issues. The notions of Go favor the latter.
--
Michael T. Jones
michae...@gmail.com
Reply all
Reply to author
Forward
0 new messages