You hear multiple terms for a package of code found in an easily callable form. For example, a procedure is a set of operations executed without calculating any return value. When you program with Java, you hear about the method, because methods are associated with objects. Java is focused on objects, so the most appropriate term is method — a method of working with that object in some meaningful way. In Kotlin, you find functions.
A function is a set of operations that don’t necessarily link to an object but always return a value. If a Kotlin function doesn’t provide a specific return value, it returns a value called Unit
. Consequently, you never use the term procedure when working with Kotlin because the procedure doesn’t exist (although you could make the argument that procedures do exist in Java). Here is an example of the Unit
return value:
val result = println("A String")You wouldn’t expectif (result is Unit) { println("result is of type Unit") println(result) }
println()
to return a value, and it doesn’t, but it does return Unit
. Because println()
is a stand-alone call not associated with an object, you always call it a function.A Minimalistic Android Activity Class
package com.example.myfirstappimport androidx.appcompat.app.AppCompatActivity import android.os.Bundle
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } }
Looking at the code above, you see the onCreate()
function, which is part of the MainActivity
class. Because onCreate()
exists as part of a class in this case, you can also call it a method. The onCreate()
method exists as a part of objects instantiated from MainActivity
. Remember that a function that appears as part of a class is more specifically called a method, even though it’s also a function.
Some ambiguity exists in other languages that use the static method, which is part of a class but is not called as part of an object. Some people argue that these methods are really functions. Kotlin gets rid of the ambiguity by using companion objects in place of static methods in classes. The point is that they really are methods in Kotlin because they’re members of the associated singleton object.
Kotlin functions have certain characteristics, as shown in the following code:
fun main(args: Array) { println(monthlyPayment(10_000.00, 5.25, 30)) println(monthlyPayment(10_000.00, 5.00, 15)) }When you run this example, you receive the expected monthly payments given a 10,000 loan, certain percentage rates, and the number of years that someone will make payments. The functions used in this example have certain characteristics:fun monthlyPayment(principle: Double, percentageRate: Double, years: Int): Double { val numPayments: Int = 12 * years val rate: Double = percentageRate / 100.00 val effectiveRate: Double = rate / 12 return (principle * effectiveRate / (1 - Math.pow(1 + effectiveRate, -numPayments.toDouble())))
- The names of the two functions are
main()
andmonthlyPayment()
. - In the body of the
monthlyPayment()
function declaration, the processor computes the monthly payments on a mortgage. You can follow this description of functions and function parameters without understanding anything about the calculations. - The body of the
monthlyPayment()
function uses certain names as placeholders. For example, in the body of themonthlyPayment()
function, the name years stands for the number of years in the mortgage's term. Likewise, the nameprincipal
stands for the total amount borrowed. - Some placeholders appear in parentheses at the beginning of the function’s declaration. The names
principal
,percentageRate
, andyears
are the function’s parameters. Each parameter is destined to stand for a particular value. But a parameter doesn't stand for a value until an app executes a function call.
The main()
function contains a call to monthlyPayment(10_0000.00, 5.25, 30)
that gives the function’s first parameter (namely, principal
) the value 10000.00
. That same call gives the function’s second parameter (percentageRate
) the value 5.25
. Finally, that function call gives the method's third parameter (years
) the value 30.
The next function call in main()
gives the monthlyPayment()
function’s parameters different values (again 10000.00
for principal
, but 5.00
for percentageRate
and 15
for years
). Each time you call a function, you supply values for the function’s parameters.
- The types of parameters in a function call must match the types of the parameters in a function declaration. The declaration of function
monthlyPayment()
has aDouble
parameter (principal
), anotherDouble
parameter (percentageRate
), and anInt
parameter (years
). Accordingly, the first function call has two Double parameters (10000.00
and5.25
) followed by anInt
parameter (30
). The second function call also has twoDouble
parameters followed by anInt
parameter.
You can declare the same function more than once, as long as each declaration has a different parameter list. For example, another monthlyPayment()
function declaration might have the same name monthlyPayment
but only two parameters: principle: Double
and percentageRate: Double
. To call this alternative monthlyPayment()
function, you write something like monthlyPayment(10_000.00, 5.00)
. In this situation, the body of the alternative monthlyPayment()
method probably contains a statement like val years: Int = 30
. You don't call this two-parameter method unless you know that the mortgage's term is 30 years.
- A function call might stand for a value. The first function call in
main()
stands for theDouble
value55.22
(or a value very close to the number55.22
). The value55.22
comes from all the calculations in the body of themonthlyPayment()
function when theprincipal
is10000.00
, thepercentageRate
is5.25
, and the number of years is30
. Near the end of themonthlyPayment()
function body, the formula
principle * effectiveRate / (1 - Math.pow(1 + effectiveRate, -numPayments.toDouble()))
has the value 55.22
, and the word return
says “send 55.22
back to the statement that called this method.” So, the end of the monthlyPayment()
function body effectively says
return 55.22
and the associated println()
statement in main()
effectively says
println(55.22)
Similarly, the second println()
function call in main()
outputs the value 79.08
. Because of the second function call's parameter values, the end of the monthlyPayment()
function body effectively says
return 79.08
and the last line in the listing effectively says
println(79.08)
A function’s declaration can end with the name of the return type. The monthlyPayment()
function declaration begins with the keyword fun
(which is short for function), followed by the function name, monthlyPayment
, a list of parameters in parentheses, and finally the keyword Double
. That's good because the value returned at the end of the method's body (either 55.22
or 79.08
) is of type Double
.