August 27, 2017
This article is on functions in Kotlin. In the previous article, I showed a simple program with a single function, main. "main" is a function with a special status in Kotlin. It's the starting point for your program. However, the definition of main follows the same structure as any function. Based on what you know of "main", a function has
A function often has a third part called a return value. Consider the familiar formula for computing the area of a rectangle: Area = length * width. Working with this formula, you would provide a length and a width and get back an area after multiplying. To turn this into Kotlin, we'd pick a name like "computeArea" and provide two parameters: length and width.
fun computeArea(length : Int, width : Int) : Int {
return length * width
}
Let's test this out. Bring up the try.kotlinlang.org web site. If you were using the site from the previous article, clear out your editor and paste in the following code. Overwite anything already in the editor.
/**
* Compute integer area of a rectangle
*/
fun computeArea(length : Int, width : Int) : Int {
return length * width
}
fun main(args: Array<String>) : Unit {
println("area of 3x4 rectangle: ${computeArea(3,4)}")
}
After the code is pasted in the editor, press the Run button. Your screen should look like the following.
Like the "main" from the previous example, the new function "computeArea" uses the fun
keyword to indicate that a function is going to be defined. After the fun keyword, the function name appears which is computeArea. There are two parameters: length and width. Length and width are paired with something called "Int" (more on this in a second). Also, there is a trailing "Int" which is the return value type. Finally, there is a block of code that makes up what the function does surrounded by curly braces {}.
In math, there are different classes of numbers such as whole numbers and decimals. The same classifications are used in Kotlin and are called data types or just types. In the computeArea function, "Int" is a data type that tells Kotlin to expect whole number values. "Int" is short for "Integer". What if you want to use the function on a rectangle with sides that are decimal values? Let's try it out. Modify the println by switching both 3's to 6.5 and the 4's to 8.1. This is an attempt to compute the area of a 6.5 by 8.1 rectangle. Run the program.
Your screen should look like the following.
We got a syntax error. This is because we've defined a function computeArea that expects Int (integer, or whole numbers) and we've given it decimals. There are a few ways to fix this. For now, let's provide a second function -- still called computeArea -- that will handle the decimals.
fun computeArea(length : Double, width : Double) : Double {
return length * width
}
fun main(args: Array<String>) : Unit {
println("area of 6.5x8.1 rectangle: ${computeArea(6.5,8.1)}")
}
Add this to the program so that your screen appears as below.
Although I mentioned earlier that there could be one and only one main function in a program, there can be multiple versions of functions sharing the same name. This is called overloading. There are some restrictions. Namely, the parameters must be different to tell Kotlin which function to use in a given instance.
"Double" is a type representing decimals. It's called "Double" and not decimal because of the number of bytes used to store the number. I'll show another way to represent a decimal called "Float" in a later article along with several other ways to represent integers and an explanation of args : Array<String>
. If you'd like to read more about this before than, here's a reference in the Kotlin docs.
Both versions of computeArea use the same parameter names length and width. However, the integer-based computeArea marks the parameters with Int where as the decimal-based computeArea marks the parameters with Double. The syntax for this is name:type such as
length : Int, width : Int
, andlength : Double, width : Double
.Notice that there is another colon used in the function definition. This is used to describe the type to be returned from the function. In the integer-based computeArea, this is ": Int". In the decimal-based computeArea, this is ": Double". In this respect, a function -- like a parameter -- has a type associated with it. This type matches the computation provided by the function.
Although both versions of computeArea multiply the parameters, the resulting type is different. That's because, unlike in mathematics, an integer number is not always compatible with a decimal. In Kotlin and other programming languages "3" and "3.0" or "3.00" are not always treated equally. When we do a numeric comparison after making a type adjustment, they are equal. This will be described more later.
So, the bodies of both computeAreas appear indentical (return length * width
). The difference lies in the return values which are different depending on what type length and width are (Int or Double).
You may have noticed that I slipped in a change with main. It's not quite the same definition as in the first article. I've added a ": Unit" on the end. I did this to show that main, while it has a special status, can be written out in a long form with a return value. "Unit" is a placeholder to support a consistent syntax, but indicates that nothing will be returned from main. That's why, unlike the computeAreas, there is no return keyword.
There are many ways to write the same thing in Kotlin! One of the big benefits of Kotlin is that you can omit code that Kotlin can infer. Leaving off the return type "Unit" for main is perfectly acceptable Kotlin code and is generally preferrable. Until we get familiar with Kotlin, I'm going to use the full syntax.
In the previous article, the main function used the Standard Library function println
to print a canned message "Hello, world!". The println used in this article is dynamic. The dollar sign / curly braces syntax indicates an expression that is evaluated and inserted into the println: ${computeArea(3,4)}
for instance. This is called a String Template Expression.
You created a custom function called computeArea and provided two versions. One version handled integer values. The other version handled decimal values. Both versions returned a value which was the result of a computation and the return
keyword. All functions have a return type and I rewrote main to return the placeholder name "Unit".
How would you go about writing a computeVolume function? The math behind such a function isn't difficult, it's Volume = length * width * height. In this case, we need a three-parameter function that multiplies the three parameters together for a return value. Try it out! Don't forget you need to provided a different println
to review your output.
By Carl Walker
President and Principal Consultant of Bekwam, Inc