Kotlin From Scratch: Packages and Basic Functions

Kotlin From Scratch: Packages and Basic Functions

Kotlin is a modern programming language that compiles to Java bytecode. It is free and open source, and promises to make coding for Android even more fun. 

In the previous article, you learned about ranges and collections in Kotlin. In this tutorial, we'll continue to learn the language by looking at how to organize code using packages, and then go on to an introduction to functions in Kotlin.

1. Packages

If you are familiar with Java, you know that Java uses packages to group related classes; for example, the java.util package has a number of useful utility classes. Packages are declared with the package keyword, and any Kotlin file with a package declaration at the beginning can contain declarations of classes, functions, or interfaces.

Declaration

Looking at the code below, we have declared a package com.chikekotlin.projectx using the package keyword. Also, we declared a class MyClass (we'll discuss classes in Kotlin in future posts) inside this package.

Now, the fully qualified name for the class MyClass is com.chikekotlin.projectx.MyClass.

In the code above, we created a top-level function (we'll get to that shortly). So similarly to MyClass, the fully qualified name for the function saySomething() is com.chikekotlin.projectx.saySomething.

Imports

In Kotlin, we use the import declaration to enable the compiler to locate the classes, functions, interfaces or objects to be imported. In Java, on the other hand, we can't directly import functions or methods—only classes or interfaces. 

We use import to access a function, interface, class or object outside the package where it was declared. 

In the code snippet above, we imported the function saySomething() from a different package, and then we executed that function.

Kotlin also supports wildcard imports using the * operator. This will import all the classes, interfaces and functions declared in the package all at once. This is not recommended, though—it's usually better to make your imports explicit.

Import Aliasing

When you have libraries that have conflicting class or function names (e.g. they each declare a function with the same name), you can use the as keyword to give that imported entity a temporary name.

Note that the temporary name is used only within the file where it was assigned.

2. Functions

A function groups together a series of code statements that perform a task. The details of the implementation of the function are hidden from the caller.

In Kotlin, functions are defined using the fun keyword, as shown in the following example:

In the code above, we defined a simple function hello() with a single parameter name of type String. This function returns a String type. The parameter definition format for functions is name: type, e.g. age: Int, price: Double, student: StudentClass.

The function above is similar to the previous one, but notice that this one has a return type of Unit. Because this function doesn't return any significant value to us—it just prints out a message—its return type is Unit by default. Unit is a Kotlin object (we'll discuss Kotlin objects in later posts) that is similar to the Void types in Java and C.

Note that if you don't explicitly declare the return type to be Unit, the type is inferred by the compiler.

Single-Line Functions

Single-line or one-line functions are functions that are just single expressions. In this function, we get rid of the braces and use the = symbol before the expression. In other words, we get rid of the function block.

The function above can be shortened into a single line:

Looking at the updated function above, you can see that we have made our code more concise by removing the curly braces {}, the return keyword, and also the return type (which is inferred by the compiler). 

You can still include the return type to be more explicit if you want.

Named Parameters

Named parameters allow more readable functions by naming the parameters that are being passed to a function when called.

In the following example, we created a function that prints my full name.

To execute the function above, we would just call it like so:

Looking at the function call above, we don't know which String type arguments equate to which function parameters (though some IDEs such as IntelliJ IDEA can help us). Users of the function will have to look into the function signature (or the source code) or documentation to know what each parameter corresponds to.

In the second function call above, we supplied the parameter names before the argument values. You can see that this function call is clearer and more readable than the previous one. This way of calling functions helps reduce the possibility of bugs that can happen when arguments of the same type are swapped by mistake.

The caller can also alter the order of the parameters using named parameters. For example:

In the code above, we swapped the argument position of the firstName with the lastName. The argument order doesn't matter with named parameters because the compiler will map each of them to the right function parameter.

Default Parameters

In Kotlin, we can give a function default values for any of its parameters. These default values are used if nothing is assigned to the arguments during the function call. To do this in Java, we'd have to create different overloaded methods.

Here, in our calCircumference() method, we modified the method by adding a default value for the pi parameter—Math.PI, a constant from the java.lang.Math package. 

When we call this function, we can either pass our approximated value for pi or use the default. 

Let's see another example.

In the following code, we tried to call the function, but it won't compile:

In the function call above, I'm passing my first name and last name to the function, and hoping to use the default value for the middle name. But this won't compile because the compiler is confused. It doesn't know what the argument "Mgbemena" is for—is it for the middleName or the lastName parameter? 

To solve this issue, we can combine named parameters and default parameters. 

Java Interoperability

Given that Java doesn't support default parameter values in methods, you'll need to specify all the parameter values explicitly when you call a Kotlin function from Java. But Kotlin provides us with the functionality to make it easier for the Java callers by annotating the Kotlin function with @JvmOverloads. This annotation will instruct the Kotlin compiler to generate the Java overloaded functions for us.

In the following example, we annotated the calCirumference() function with @JvmOverloads.

The following code was generated by the Kotlin compiler so that Java callers can then choose which one to call.

In the last generated Java method definition, the pi parameter was omitted. This means that the method will use the default pi value.

Unlimited Arguments

In Java, we can create a method to receive an unspecified number of arguments by including an ellipsis (...) after a type in the method's parameter list. This concept is also supported by Kotlin functions with the use of the vararg modifier followed by the parameter name.

The vararg modifier allows callers to pass in a comma-separated list of arguments. Behind the scenes, this list of arguments will be wrapped into an array. 

When a function has multiple parameters, the vararg parameter is typically the last one. It is also possible to have parameters after the vararg, but you'll need to use named parameters to specify them when you call the function. 

For example, in the code above, the parameter with the vararg modifier is in the last position in a multiple parameters list (this is what we usually do). But what if we don't want it in the last position? In the following example, it is in the second position.

As you can observe in the updated code above, we used named arguments on the last parameter to solve this.

Spread Operator

Let's say we want to pass an array of integers to our printNumbers() function. The function expects the values to be unrolled into a list of parameters, though. If you try to pass the array directly into printNumbers(), you'll see that it won't compile. 

To solve this problem, we need to use the spread operator *. This operator will unpack the array and then pass the individual elements as arguments into the function for us. 

By inserting the spread operator * in front of intsArray in the function's arguments list, the code now compiles and produces the same result as if we had passed the elements of intsArray as a comma-separated list of arguments. 

Return Multiple Values

Sometimes we want to return multiple values from a function. One way is to use the Pair type in Kotlin to create a Pair and then return it. This Pair structure encloses two values that can later be accessed. This Kotlin type can accept any types you supply its constructor. And, what's more, the two types don't even need to be the same. 

In the function above, we constructed a new Pair by passing the userName and userState variables as the first and second arguments respectively to its constructor, and then returned this Pair to the caller.

Another thing to note is that we used a function called require() in the getUserNameAndState() function. This helper function from the standard library is used to give our function callers a precondition to meet, or else an IllegalArgumentException will be thrown (we'll discuss Exceptions in Kotlin in a future post). The optional second argument to require() is a function literal returning a message to be displayed if the exception is thrown. For example, calling the getUserNameAndState() function and passing -1 as an argument to it will trigger:

IntelliJ IDEA code execution result 

Retrieving Data From Pair

In the code above, we accessed the first and second values from the Pair type by using its first and second properties.

However, there is a better way of doing this: destructuring.

What we have done in the updated code above is to directly assign the first and second values of the returned Pair type to the variables name and state respectively. This feature is called destructuring declaration.

Triple Return Values and Beyond

Now, what if you want to return three values at once? Kotlin provides us with another useful type called Triple.

I am sure some of you are wondering what to do if you want to return more than three values. The answer for that will be in a later post, when we discuss Kotlin's data classes.

Conclusion

In this tutorial, you learned about the packages and basic functions in the Kotlin programming language. In the next tutorial in the Kotlin From Scratch series, you'll learn more about functions in Kotlin. See you soon!

To learn more about the Kotlin language, I recommend visiting the Kotlin documentation. Or check out some of our other Android app development posts here on Envato Tuts+!

Source: Tuts Plus

About the Author