Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Default arguments vs overloads, when to use which

In Kotlin there are two ways to express an optional parameter, either by specifying default argument value:

fun foo(parameter: Any, option: Boolean = false) { ... }

or by introducing an overload:

fun foo(parameter: Any) = foo(parameter, false)
fun foo(parameter: Any, option: Boolean) { ... }

Which way is preferred in which situations?

What is the difference for consumers of such function?

like image 276
Ilya Avatar asked Sep 27 '16 20:09

Ilya


People also ask

When should a default argument be used?

Default Arguments in C++In case any value is passed, the default value is overridden. 1) The following is a simple C++ example to demonstrate the use of default arguments. Here, we don't have to write 3 sum functions; only one function works by using the default values for 3rd and 4th arguments.

When should default arguments be preferred over function overloading and vice versa?

A default parameter can only supply a value of the same type as a parameter. An overloaded function can use completely different parameters. That's just one difference. Sometimes you want to use different parameter types for different overloads.

What are the advantages of default arguments over function overloading?

Using default arguments reduces the number of functions you need to find, because it reduces the number of overloads. It makes sure that as time goes by, the actual logic of the two overloads with different numbers of arguments don't drift apart, intentionally or accidentally.

Are default arguments reasonable in the presence of overloading justify your answer?

No you cannot overload functions on basis of value of the argument being passed, So overloading on the basis of value of default argument is not allowed either. You can only overload functions only on the basis of: Type of arguments. Number of arguments.


1 Answers

In Kotlin code calling other Kotlin code optional parameters tend to be the norm over using overloads. Using optional parameters should be you default behavior.

Special cases FOR using defaulted values:

  • As a general practice or if unsure -- use default arguments over overrides.

  • if you want the default value to be seen by the caller, use default values. They will show up in IDE tooltips (i.e. Intellij IDEA) and let the caller know they are being applied as part of the contract. You can see in the following screenshot that calling foo() will default some values if values are omitted for x and y:

    enter image description here

    Whereas doing the same thing with function overloads hides this useful information and just presents a much more messy:

    enter image description here

  • using default values causes bytecode generation of two functions, one with all parameters specified and another that is a bridge function that can check and apply missing parameters with their defaulted values. No matter how many defaulted parameters you have, it is always only two functions. So in a total-function-count constrained environment (i.e. Android), it can be better to have just these two functions instead of a larger number of overloads that it would take to accomplish the same job.

Cases where you might not want to use default argument values:

  • When you want another JVM language to be able to use the defaulted values you either need to use explicit overloads or use the @JvmOverloads annotation which:

    For every parameter with a default value, this will generate one additional overload, which has this parameter and all parameters to the right of it in the parameter list removed.

  • You have a previous version of your library and for binary API compatibility adding a default parameter might break compatibility for existing compiled code whereas adding an overload would not.

  • You have a previous existing function:

    fun foo() = ...
    

    and you need to retain that function signature, but you also want to add another with the same signature but additional optional parameter:

    fun foo() = ...
    fun foo(x: Int = 5) = ...   // never can be called using default value
    

    You will not be able to use the default value in the 2nd version (other than via reflection callBy). Instead all foo() calls without parameters still call the first version of the function. So you need to instead use distinct overloads without the default or you will confuse users of the function:

    fun foo() = ...  
    fun foo(x: Int) = ...
    
  • You have arguments that may not make sense together, and therefore overloads allow you to group parameters into meaningful coordinated sets.

  • Calling methods with default values has to do another step to check which values are missing and apply the defaults and then forward the call to the real method. So in a performance constrained environment (i.e. Android, embedded, real-time, billion loop iterations on a method call) this extra check may not be desired. Although if you do not see an issue in profiling, this might be an imaginary issue, might be inlined by the JVM, and may not have any impact at all. Measure first before worrying.

Cases that don't really support either case:

In case you are reading general arguments about this from other languages...

  • in a C# answer for this similar question the esteemed Jon Skeet mentions that you should be careful using defaults if they could change between builds and that would be a problem. In C# the defaulting is at the call site, whereas in Kotlin for non-inlined functions it is inside of the (bridge) function being called. Therefore for Kotlin it is the same impact for changing hidden and explicit defaulting of values and this argument should not impact the decision.

  • also in the C# answer saying that if team members have opposing views about use of defaulted arguments then maybe don't use them. This should not be applied to Kotlin as they are a core language feature and used in the standard library since before 1.0 and there is no support for restricting their use. The opposing team members should default to using defaulted arguments unless they have a definitive case that makes them unusable. Whereas in C# it was introduced much later in the life cycle of that language and therefore had a sense of more "optional adoption"

like image 53
8 revs, 2 users 99% Avatar answered Sep 30 '22 13:09

8 revs, 2 users 99%