Kotlin supports function overloading, which is a form of polymorphism where the compiler deduces which function should get called based on the type and position of the arguments. When we overload functions, we create functions that have the same name, but different return types or arguments. This allows us to write code that is customized based on the type of the parameters based on the function. Let’s begin with an example.
class Bob(val name : String = "Bob") /** * Here are five functions with the same name. Each function is resolved * based on the type of parameters that are supplied. */ fun foo(name : String) { println("Inside foo(String)") println(name) } fun foo(num : Int){ println("Inside foo(Int)") println(num) } fun foo(bob : Bob){ println("Inside of foo(Bob)") println(bob.name) } fun foo(any : Any){ println("Inside of foo(Any)") println(any) } fun foo(name : String, any : Any){ println("Inside of foo(name, any)") println("$name, $any") }
Here are five functions named foo. The compiler can figure out which function to use because all five of our foo functions take a different type as an argument. So when we call foo(“Hello World”) the version of foo that takes a String parameter is used because “Hello World” is a String. Likewise, when we call foo(12), the compiler will choose the foo(Int) version because 12 is an int. The final version of foo takes two parameters, String and Any. It will get called when we supply a String and another object so foo(“Hello”, “Bob Belcher”) matches to foo(String, Any) as well as foo(“Bob is #”, 1).
Optional Arguments
The designers of Kotlin realized that while function overloading is useful, it can also turn into verbose code. Kotlin supports optional arguments and named arguments to help address the problem.
fun foo(num : Long = 0, name : String = "", bob : Bob = Bob(), any : Any = object{ override fun toString() = "Object" }){ println("Inside of default argument function") println(num) println(name) println(bob) println(any) }
When this code compiles, the compiler will basically overload the foo function for us, but we can avoid writing a bunch of overloaded function when we use optional arguments correctly. This version of foo can be called by writing foo(), which uses all of the defaults, foo(num = 12L), which uses the defaults except for the num parameter which is set to 12. We can also write foo(any = Bob()), and so on.
Putting it Together
Here is a sample driver program that shows off function overloading and optional arguments.
package ch1.overloading class Bob(val name : String = "Bob") /** * Here are five functions with the same name. Each function is resolved * based on the type of parameters that are supplied. */ fun foo(name : String) { println("Inside foo(String)") println(name) } fun foo(num : Int){ println("Inside foo(Int)") println(num) } fun foo(bob : Bob){ println("Inside of foo(Bob)") println(bob.name) } fun foo(any : Any){ println("Inside of foo(Any)") println(any) } fun foo(name : String, any : Any){ println("Inside of foo(name, any)") println("$name, $any") } //Note that we can also use default arguments in Kotlin //which lets us reduce function overloading fun foo(num : Long = 0, name : String = "", bob : Bob = Bob(), any : Any = object{ override fun toString() = "Object" }){ println("Inside of default argument function") println(num) println(name) println(bob) println(any) } fun main (args : Array<String>){ //Resolves to foo(String) because "Hello World" is a String foo("Hello World") //Resolves to foo(Int) because 1 is an int foo(1) //Resolve to foo(Bob) because Bob is Bob foo(Bob()) //Resolves to foo(Any) because the object expression matches //to Any, which is the base type of all objects in Kotlin foo(object { override fun toString() = "Object"}) //Matches to foo(String, Any) foo("Hello ", Bob()) foo() //Called with optional arguments. foo(num = 2L) //Called with only using one of the optional arguments }
When run, we get this output
Inside foo(String) Hello World Inside foo(Int) 1 Inside of foo(Bob) Bob Inside of foo(Any) Object Inside of foo(name, any) Hello , ch1.overloading.Bob@3caeaf62 Inside of default argument function 0 ch1.overloading.Bob@6a38e57f Object Inside of default argument function 2 ch1.overloading.Bob@5577140b Object