How to spread default arguments between functions in Kotlin?

Kotlin has default arguments for function parameters and constructors . I now have a function

fun foo(bar: String = "ABC", baz: Int = 42) {} 

and I want to call it from different places, but also keep the ability not to pass arguments and use the default value instead.

I know, I can declare default arguments in calling functions

 fun foo2(bar: String = "ABC", baz: Int = 42) { // do stuff foo(bar, baz) } fun foo3(bar: String = "ABC", baz: Int = 42) { // do other stuff foo(bar, baz) } 

but now my default parameter in foo pointless, as it is always overwritten, and I duplicated the default arguments in all calling functions. This is not very DRY.

Is there a better way to propagate default arguments?

+5
source share
3 answers

Instead of three functions with the same default arguments:

 fun foo(bar: String = "ABC", baz: Int = 42) fun foo2(bar: String = "ABC", baz: Int = 42) fun foo3(bar: String = "ABC", baz: Int = 42) 

Create a wrapper class that takes arguments and has functions without parameters:

 class Foo(val bar: String = "ABC", val baz: Int = 42) { fun foo() { /* ... */ } fun foo2() { // ... foo() } fun foo3() { // ... foo() } } 
+2
source

Answering my own question, as recommended by recommendations .


What you can do is declare the parameters in the calling functions as nullable and use null as the default argument:

 fun foo2(bar: String? = null: Int? = null) { // do stuff foo(bar, baz) } fun foo3(bar: String? = null, baz: Int? = null) { // do other stuff foo(bar, baz) } 

Then use one of the elvis operator to use the default values ​​when null provided.

 fun foo(bar: String? = null, baz: Int? = null) { val realBar = bar ?: "ABC" val realBaz = baz ?: 42 } 

If you are dealing with a class instead of a function, you can pull out the constructor property and assign it a default value:

 class Foo(bar: String? = null, baz: Int? = null) { val bar = bar ?: "ABC" val baz = baz ?: 42 } 

Alternatively, say if your class is a data class and you want to have properties in the main constructor, you can declare a factory method to handle the default values:

 class Foo(val bar: String, baz: Int) { companion object { fun create(bar: String? = null, baz: Int? = null) = Foo(bar ?: "ABC", baz ?: 42) } } 
+1
source

If you have several functions that take the same arguments (with the same default values), then this is the smell of code, suggesting that these parameters are closely related and must live inside their own class.

 data class FooArgs( val bar: String = "ABC", val baz: Int = 42 ) fun foo( args: FooArgs = FooArgs() ) { /* ... */} fun foo2( args: FooArgs = FooArgs() ) { ... foo(args) } fun foo3( args: FooArgs = FooArgs() ) { ... foo(args) } 

If foo and / or foo2 , foo3 use only their arguments, then further refactoring will move foo and foo2 to the FooArgs class, which will lead to a similar solution @nhaarman's answer

0
source

Source: https://habr.com/ru/post/1260077/


All Articles