Kotlin Functions - mariamaged/Java-Android-Kotlin GitHub Wiki
Kotlin - Functions
Trivial Functions
A function that does not require any parameters.
fun trivial() {
println(1 + 1)
}
trivial()
Functions with Parameters
fun lessTrivial(left: Int, right: Int) {
println(left + right)
}
- Parameters are a comma delimited list of paired values:
- The name of the parameter.
- And its type.
Functions with Return Types
The functions shown so far are Kotlin's equivalent of Java methods that return void, in that they are not returning any values to the caller.
- However, as with functions and methods in most programming languages, Kotlin functions can return values, using the return keyword.
- However, to be able to return a value, the functions needs to declare the
type
of what is being returned. - In Kotlin, it is declared at the
end
, after the closing parentheses, separated by a colon.
fun simpleReturn(left: Int, right: Int) :Int {
return left + right;
}
val result = simpleReturn(1, 1);
println(result)
Local Variables
- Variables declared inside a function are considered to be local variables.
- They are available inside of the function but not outside of it.
- And those variables go "out of scope" once the function returns.
- So, we could rework our function to use a local variable to hold into the calculation:
fun actLocally(left: Int, right: Int) :Int {
val result = left + right;
return result;
}
println(actLocally(1, 1))
Fancier Functions
Expression Bodies
Frequently, our function bodies are lines of code wrapped in braces, as shown above.
- Sometimes, you will encounter functions that are declared using an = instead.
- It is designed to
simplify cases
where the entire method implementation is a single expression, such as adding two numbers together. - Here, we replace:
- A pair of braces.
- And a return keyword.
with an =, which makes this code less verbose.
fun expressionBody(left: int, right: Int) = left + right
println(expressionBody(1, 1))
Expression Bodies and Types
- Another thing that we eliminated in this example is the return type.
- We did not need to declare that
expressionBody()
returns anInt
, as thecompiler
can determine that on its own.- It knows what the type of
left
is. - And it knows what the type of
right
is. - It even knows what the type of
left + right
is. - So, it knows the type of
expressionBody()
as a result.
- It knows what the type of
However, sometimes, you will need to override that type
.- For example, there will be cases where the expression evaluates to one type, but you want the function to return a supertype.
- In those cases, you just add the : syntax for declaring the return type:
fun expressionType(left: int, right, Int) :Number = left + right;
println(expressionType(1, 1));
Why Bother?
- In the end, this may not seem like a "big win", for two reasons:
- We are only saving a few characters.
- Not that many functions would appear to be simple enough that their entire implementation can be a single expression.
First Argument
- The first argument is true: we are not saving much on a per-function basis.
- However, these simplifications
add up over time
. - A lot of focus in Kotlin is on offering these small simplifications, in a lot of places, which combine to make Kotlin code much more concise than the equivalent code in Java and other languages.
Second Argument
- It turns out that a lot more things in Kotlin can be written in terms of expressions than you might think.
Default Parameters Values
- One annoyance in Java is that it lacks the concept of
default parameter values
that you have in other languages.
JavaScript Example
function increment(base, amount = 1) {
// something yummy
}
Ruby Example
def increment(base, amount = 1)
# something yummy
end
Kotlin
- Here, we call
increment()
with either one or two values.- If we only supply two values, then the caller controls base and amount.
- If we only supply one value, the default value of 1 will be used for amount.
fun increment(base: Int, amount: Int = 1) = base + amount
println(increment(1)) // Prints 2.
Named Parameters
Functions with a lot of default values are often called using named parameters.
- In the form of a call,
- Rather than identifying parameters by the
order
in which they appear in the call. - You
explicitly
state thename
of the parameter in the call itself.
- Rather than identifying parameters by the
fun increment(base:Int, amount: Int = 1) = base + amount
println(increment(base = 1))
println(increment(amount = 10, base = 1))
- You can even "mix and match" positional parameters and names parameters.
fun increment(base: Int, amount: Int = 1) = base + amount
println(increment(1, amount = 10))
- In this particular example, we are not gaining much from this syntax.
- However, complex functions with lots of default parameter values can gain a lot from this.
- Here, six of the parameters have default values defined, and so they are optional when we call
iCanHazCookie()
.
fun iCanHazCookie(name: String,
value: String,
maxAge: Long? = null,
expires: LocalDateTime? = null,
domain: String? = null,
path: String? = null,
secure: Boolean = false,
httpOnly: Boolean = false) : String {
// Rest of code for creating a cookie header.
}
Positional Parameters Scenario:
- Suppose that I want to create a cookie with a particular path, but I am willing to accept the
defaults
for the remainingfive optional parameters
.- If we were struck with
positional parameters
, we would have to call it like this.- In effect, the
first three optional parameters
areno longer optional
, because we need them asplaceholders
.
val cookieHeader = iCanHazCookie("foo", "bar", null, null, null, "/");
Named parameters scenario:
// First option.
val cookieHeader = icanHazCookie(name = "foo", value = "bar", path = "/");
// Second option.
val cookieHeader = icanHazCookie("foo", "bar", path = "/");