The castFireball function you defined, with its default argument for the numFireballs parameter, can be called two ways:
castFireball() castFireball(numFireballs)
When a function has multiple implementations, like castFireball, it is said to be overloaded. Overloading is not always the result of a default argument. You can define multiple implementations with the same function name. To see what this looks like, open the Kotlin REPL (Tools → Kotlin → Kotlin REPL) and enter these function definitions:
Listing 4.7 Defining an overloaded function (REPL)
fun performCombat() { println("You see nothing to fight!") } fun performCombat(enemyName: String) { println("You begin fighting $enemyName.") } fun performCombat(enemyName: String, isBlessed: Boolean) { if (isBlessed) { println("You begin fighting $enemyName. You are blessed with 2X damage!") } else { println("You begin fighting $enemyName.") } }
You have defined three implementations of performCombat. All are Unit functions, with no return value. One takes no arguments. One takes a single argument, the name of an enemy. And the last takes two arguments: the enemy’s name and a Boolean indicating whether the player is blessed. Each function generates a different message (or messages) through calls to println.
When you call performCombat, how will the REPL know which one you want? It will evaluate the arguments you pass in and find the implementation that matches the number and type of the arguments. In the REPL, call each of the implementations of performCombat, as shown:
Listing 4.8 Calling the overloaded functions (REPL)
performCombat() performCombat("Ulrich") performCombat("Hildr", true)
Your output will read:
You see nothing to fight! You begin fighting Ulrich. You begin fighting Hildr. You are blessed with 2X damage!
Notice that the implementation of the overloaded function was selected based on how many arguments you provided.