Function Overloading

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
Advertisements

One thought on “Function Overloading”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s