Kotlin Companion Objects

Kotlin has a companion object feature that lets us associate a single object with a class. Companion objects can serve a number of purposes. For example, we may wish to associate methods such as factory methods with a companion object rather than an instance of a class. Likewise, we can use companion object to store constants or count the number of times an instance of a class was created.

Here is an example Burger class that uses a companion object.

class Burger(val name : String) {
    
    //Create and define a companion object.
    companion object SpecialBurgers {
        //Here are some constants
        const val TOP_BUN_BURGER = "Top Bun Burger"
        const val NATIONAL_PASS_THYME_BURGER = "National Pass Thyme Burger"
        const val KALE_MARY_BURGER = "Kale Mary Burger"
        const val SNIPWRECKED_BURGER = "Snipwrecked Burger"

        //Count the number of burgers that were created
        private var _instances = 0
        
        val burgers : Int
            get() = _instances

        fun burgerList() =
                listOf(TOP_BUN_BURGER,
                        NATIONAL_PASS_THYME_BURGER,
                        KALE_MARY_BURGER,
                        SNIPWRECKED_BURGER)
    }

    init {
        check(name in burgerList(), { "$name not in Burger List"})
        
        //Increment the number of burgers created
        _instances++
    }
}

The Burger class has a companion object called SpecialBurgers. Readers will notice that creating a companion object is almost the same as writing a class. The difference is that the companion object is instantiated with the JVM loads the Burger class into memory. Companion objects can have init blocks, but they are not allowed to have constructors. Finally, we are not allowed to create instances of companion objects.

The SpecialBurgers object has four constants, a variable called _instances, and some methods. The init block in Burger increments _instances. It also calls burgerList() found in the companion object to check if the name variable is found in burgerList(). If the name isn’t in burgerList(), the program will throw an exception.

We can use the companion object later on by using the class name followed by the dot (.) syntax. Here is the later half of the program that uses the companion object.

fun main(args : Array<String>){
    val badBurger = "Barley Davidson Burger"

    try {
        //This will throw an exception because of the
        //check in Burger's init block
        val barleyBurger = Burger(badBurger)
    } catch (e : Exception){
        println("$badBurger is not in ${Burger.burgerList()}")
    }

    //We can reference the KALE_MARY_BURGER constant found in 
    //Burger's companion object
    val firstBurger = Burger.KALE_MARY_BURGER
    val kaleBurger = Burger(firstBurger)
    
    //This next line uses the burgers property found in SpecialBurgers to
    //print how many burgers we have created
    println("Created ${kaleBurger.name} and we have served ${Burger.burgers} burgers")

    //We can also reference our burger constants directly
    val snipsBurger = Burger(Burger.SNIPWRECKED_BURGER)
    println("Created ${snipsBurger.name} and we have served ${Burger.burgers} burgers")

    //Finally, the SpecialBurgers is an actual object, so we
    //can store it in a variable when needed
    val burgerCompanion = Burger.SpecialBurgers
    
    val topBunBurger = Burger(burgerCompanion.TOP_BUN_BURGER)
    println("Created ${topBunBurger.name} and we have served ${Burger.burgers} burgers")
}

We use the SpecialBurgers object in a few different ways in main. First, we try and make a barleyBurger. Creating a barleyBurger throws an exception because it’s burger name, “Barley Davidson Burger” is fails the name check found in Burger’s init block.

The next burger we try making is the kaleBurger. First we show how to store a value found in Burger.KALE_MARY_BURGER in a variable. As you can see, it acts just like any other variable. The next line creates an instance of Burger by passing firstBurger to the constructor of Burger. Creating the kaleBurger succeeds and the init block in Burger increments the _instances variable by one. The next line prints out the name of the burger and how many burgers we have served. Notice that it’s Burger.burgers because we are using the burger property found on SpecialBurgers.

The snipsBurger is created by passing Burger.SNIPWRECKED_BURGER direclty into the Burger’s constructor. Once against _instances is incremented and we now have served two specialty burgers. The final burger is created by first assigning SpecialBurgers to a variable first. Since SpecialBurgers is an object, it can be assigned to other references when needed. We create our topBunBurger by using burgerCompanion.TOP_BUN_BURGER.

Putting it Together

Here is the entire program, followed by the output.

package ch4.companionobjects

class Burger(val name : String) {
    companion object SpecialBurgers {
        //Heere are some constants
        const val TOP_BUN_BURGER = "Top Bun Burger"
        const val NATIONAL_PASS_THYME_BURGER = "National Pass Thyme Burger"
        const val KALE_MARY_BURGER = "Kale Mary Burger"
        const val SNIPWRECKED_BURGER = "Snipwrecked Burger"

        //Count the number of burgers that were created
        private var _instances = 0

        val burgers : Int
            get() = _instances

        fun burgerList() =
                listOf(TOP_BUN_BURGER,
                        NATIONAL_PASS_THYME_BURGER,
                        KALE_MARY_BURGER,
                        SNIPWRECKED_BURGER)
    }

    init {
        check(name in burgerList(), { "$name not in Burger List"})

        //Increment the number of burgers created
        _instances++
    }
}

fun main(args : Array<String>){
    val badBurger = "Barley Davidson Burger"

    try {
        //This will throw an exception because of the
        //check in Burger's init block
        val barleyBurger = Burger(badBurger)
    } catch (e : Exception){
        println("$badBurger is not in ${Burger.burgerList()}")
    }

    //We can reference the KALE_MARY_BURGER constant found in
    //Burger's companion object
    val firstBurger = Burger.KALE_MARY_BURGER
    val kaleBurger = Burger(firstBurger)

    //This next line uses the burgers property found in SpecialBurgers to
    //print how many burgers we have created
    println("Created ${kaleBurger.name} and we have served ${Burger.burgers} burgers")

    //We can also reference our burger constants directly
    val snipsBurger = Burger(Burger.SNIPWRECKED_BURGER)
    println("Created ${snipsBurger.name} and we have served ${Burger.burgers} burgers")

    //Finally, the SpecialBurgers is an actual object, so we
    //can store it in a variable when needed
    val burgerCompanion = Burger.SpecialBurgers

    val topBunBurger = Burger(burgerCompanion.TOP_BUN_BURGER)
    println("Created ${topBunBurger.name} and we have served ${Burger.burgers} burgers")
}

This is the output when run.

Barley Davidson Burger is not in [Top Bun Burger, National Pass Thyme Burger, Kale Mary Burger, Snipwrecked Burger]
Created Kale Mary Burger and we have served 1 burgers
Created Snipwrecked Burger and we have served 2 burgers
Created Top Bun Burger and we have served 3 burgers

References

https://kotlinlang.org/docs/reference/properties.html

Advertisements

Kotlin and OOP

Like many JVM languages such as Java, Scala, Groovy, etc, Kotlin supports OOP (Object Orientated Programming). OOP allows developers to create reusable and self-contained software modules known as classes where data and behavior are grouped together and contained within the said class. Such packaging allows developers to think in terms of components when solving a software problem and can improve code reuse and maintainability.

There are often four terminologies that are discussed when explaining OOP. The first term is encapsulation. Encapsulation refers to combining a programs data with the behaviors that operate on the said data. This is different than procedural based programming that treats data and behavior as two seperate concerns. However, encapsulation goes further than just simply grouping behavior and data. It also means that we protect our data inside of the class by only allowing the class itself to use the data. Other users of the class may only work on class data through the class’s public interface.

This takes us into the next concept of OOP, Abstraction. A well designed and encapsulated class functions as a black box. We may use the class, but we may only use it through it’s public interface. The details of how the class works internally are taken away from or Abstracted, from the clients of the class. A car is commonly used as an example of abstraction. We can drive the car using the steering wheel and the foot pedals, but we do not get into the internals of the car and fire the fuel injection at the right time. The car takes care of the details of making it move. We only operate it through its public interface. The details of how a car works are abstracted from us.

OOP promotes code reuse through inheritance. The basic idea is that we can use one class as a template for a more specialized version of a class. For example, we may have a class that represents a Truck. As time went on, we realized that we needed a four wheel drive truck. Rather than writing an entirely new class, we simply create a four wheel drive truck from the truck class. The four wheel drive truck inherits all of the computer code from the truck class, and the developer only needs to focus on code that makes it a four wheel drive truck. Such code reuse not only saves on typing, but it also helps to reduce debugging since developers are free to leverage already tested computer code.

Related to inheritence is polymorphism. Polymorphism is a word that means many-forms. For developers, this means that one object may act as if it were another object. Take the truck example above as an example. Since a four wheel drive truck inherited from truck, the four wheel drive truck may be used whenever the computer code expects a truck. Polymorphism goes a set further in allowing the program to act different depending on the context in which certain portions of computer code are used.

Koltin is a full fleged OOP language (although it does support other programming styles also). The language brings all of the OOP concepts discussed above to the fore-front by allowing us to write classes, abstract their interfaces, extend classes, and even use them in different situations depending on context. Let’s begin by looking at a very basic example of how to write and create a class in Kotlin.

package ch1

class Circle(
        //Define data that gets associated with the class
        private val xPos : Int = 20,
        private val yPos : Int = 20,
        private val radius : Int = 10){

    //Define behavior that uses the data
    override fun toString() : String =
            "center = ($xPos, $yPos) and radius = $radius"
}

fun main(args: Array<String>){
    val c = Circle() //Create a new circle
    val d = Circle(10, 10, 20)
    
    println( c.toString() ) //Call the toString() function on c
    println( d.toString() ) //Call the toString() function on d
}

In the above program, we have a very basic example of a Kotlin class called Circle. The code inside of lines 3-12 tell the Kotlin compiler how to construct objects of Type Circle. The circle has three properties (data): xPos, yPos, and radius. It also has a function that uses the data: toString().

In the bottom half of the program, the main method creates two new circle objects (c and d). The circle c has the default values of 20, 20, and 10 for xPos, yPos, and radius because we used the no parenthesis constructor (). Lines 5-7 in the circle class tell the program to simply use 20, 20, and 10 as default values in this case. Circle d has different valeus for xPos, yPos, and radius because we supplied 10, 10, 20 to the constructor. Thus we have an example of polymorphism in this program because two different constructors were used depending on the program’s context.

When we print on lines 18 and 19, we get two different outputs. When we call c.toString(), we get the String “center = (20, 20) and radius = 10” printed to the console. Calling toString() on d results in “center = (10, 10) and radius = 20”. This works because both c and d are distinct objects in memory and each have there own values for xPos, yPos, and radius. The toString() function acts on each distinct object, and thus, the output of toString() reflects the state of each Circle object.

Kotlin Spring Data Delegation

Kotlin provides many features that can be really useful when working with Spring. I was doing a website for my fiancee where I found an excellent use case of Kotlin’s Delegation and Extension function that I am going to share with readers today.

Code

KotlinDelegationApplication.kt

package com.stonesoupprogramming.delegation.kotlindelegation

import org.hibernate.validator.constraints.NotBlank
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Controller
import org.springframework.stereotype.Service
import org.springframework.ui.Model
import org.springframework.validation.BindingResult
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.ModelAttribute
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestMapping
import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.Id
import javax.transaction.Transactional
import javax.validation.Valid
import javax.validation.constraints.NotNull

@SpringBootApplication
class KotlinDelegationApplication

enum class FamilyMemberType {Father, Mother, Daughter, Son}

//Basic entity class
@Entity
data class Belchers(
        @field: Id
        @field: GeneratedValue
        var id : Long? = null,

        @field: NotBlank(message = "Need a name!")
        var name : String = "",

        @field: NotNull(message = "Assign to a family type")
        var familyMemberType: FamilyMemberType? = null
)

//Now we are going to define a JpaRepository to handle persistence
interface BelchersRepository : JpaRepository

//Here is a service class that contains our business logic
@Service
@Transactional
class BelchersService(
        //Inject an instance of BelchersRepository
        @field : Autowired
        val belchersRepository: BelchersRepository) : BelchersRepository by belchersRepository {
    /**
     * The above line demonstrates Kotlin's delegation syntax. It works by specifying a variable whose type
     * is an interface (no concrete or abstract classes). After the colon, we specify the name of the interface
     * and the variable that provides the object we are using for delegation. The Kotlin compiler builds out all of
     * methods included in the interface and routes calls to those method to the delegate object.
     *
     * In this example, BelcherService gets all of the methods included in BelchersRepository and the belcherRepository
     * object handles the implementation of all BelcherRepository method unless we override them.
     */

    /**
     * Here is an example of where we override only one method of BelchersRepository
     *  so that we can customize the behavior.
     */
    override fun <s> save(entity: S): S {
        val formattedName = entity?.name?.split(" ")?.map { it.toLowerCase().capitalize() }?.joinToString(" ")
        if(formattedName != null){
            entity.name = formattedName
        }
        return belchersRepository.save(entity)
    }
}

//Example MVC controller
@Controller
@RequestMapping("/")
class IndexController (
        @field: Autowired
        val belchersService: BelchersService) {

    @ModelAttribute("belcherFamily")
    fun fetchFamily() = belchersService.findAll()

    @ModelAttribute("belcher")
    fun fetchBelcher() = Belchers()

    @GetMapping
    fun doGet() = "index"

    @PostMapping
    fun doPost(@Valid belcher : Belchers, bindingResult: BindingResult, model: Model) : String {
        var entity = belcher

        if(!bindingResult.hasErrors()){
            belchersService.save(belcher)
            entity = Belchers()
        }

        //Notice the use of extension functions to keep the code concise
        model.addBelcher(entity)
        model.addBelcherFamily()

        return "index"
    }

    //Some private extension functions which tend to be really useful in Spring MVC
    private fun Model.addBelcherFamily(){
        addAttribute("belcherFamily", belchersService.findAll())
    }

    private fun Model.addBelcher(belcher: Belchers = Belchers()){
        addAttribute("belcher", belcher)
    }
}

fun main(args: Array) {
    SpringApplication.run(KotlinDelegationApplication::class.java, *args)
}

index.html

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
      xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Kotlin Delegation Example</title>

    <script src="http://code.jquery.com/jquery-3.2.1.js"
            integrity="sha256-DZAnKJ/6XZ9si04Hgrsxu/8s717jcIzLy3oi35EouyE="
            crossorigin="anonymous"></script>

    <!-- Latest compiled and minified CSS & JS -->
    <link rel="stylesheet" media="screen" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

    <style>
        button {
            margin-top: 10px;
        }
    </style>
</head>
<body>
<div class="jumbotron">
    <div class="container">
        <h1>Kotlin Delegation</h1>
        <p>Web demonstration showing how Kotlin's delegation features pairs with Spring Data</p>
    </div>
</div>

<div class="container">
    <div class="row" th:if="${belcherFamily.size() > 0}">
        <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
            <table class="table table-striped table-hover">
                <thead>
                <tr>
                    <th>ID</th>
                    <th>Name</th>
                    <th>Family Member Type</th>
                </tr>
                </thead>
                <tbody>
                <tr th:each="belcher : ${belcherFamily}">
                    <td th:text="${belcher.id}"></td>
                    <td th:text="${belcher.name}"></td>
                    <td th:text="${belcher.familyMemberType}"></td>
                </tr>
                </tbody>
            </table>
        </div>
    </div>

    <div class="row">
        <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
            <form th:action="@{/}" method="post" th:object="${belcher}">
                <legend>Add a Family Member</legend>

                <div th:class="${#fields.hasErrors('name') ? 'form-group has-error' : 'form-group'}">
                    <label for="name">Name</label>
                    <input class="form-control" name="name" id="name" th:field="*{name}" />
                    <span th:if="${#fields.hasErrors('name')}" th:errors="*{name}" class="help-block"></span>
                </div>

                <select name="type" id="type" class="form-control" th:field="*{familyMemberType}">
                    <option th:each="value : ${T(com.stonesoupprogramming.delegation.kotlindelegation.FamilyMemberType).values()}"
                            th:value="${value}" th:text="${value}" />
                </select>

                <button class="btn btn-primary">Submit</button>
            </form>
        </div>
    </div>
</div>
</body>
</html>

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.stonesoupprogramming.delegation</groupId>
	<artifactId>kotlin-delegation</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>kotlin-delegation</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.6.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<kotlin.compiler.incremental>true</kotlin.compiler.incremental>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
		<kotlin.version>1.1.3-2</kotlin.version>
		<thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
		<thymeleaf-layout-dialect.version>2.1.1</thymeleaf-layout-dialect.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.hsqldb</groupId>
			<artifactId>hsqldb</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.jetbrains.kotlin</groupId>
			<artifactId>kotlin-stdlib-jre8</artifactId>
			<version>${kotlin.version}</version>
		</dependency>
		<dependency>
			<groupId>org.jetbrains.kotlin</groupId>
			<artifactId>kotlin-reflect</artifactId>
			<version>${kotlin.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
		<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
			<plugin>
				<artifactId>kotlin-maven-plugin</artifactId>
				<groupId>org.jetbrains.kotlin</groupId>
				<version>${kotlin.version}</version>
				<configuration>
					<compilerPlugins>
						<plugin>spring</plugin>
					</compilerPlugins>
					<jvmTarget>1.8</jvmTarget>
				</configuration>
				<executions>
					<execution>
						<id>compile</id>
						<phase>compile</phase>
						<goals>
							<goal>compile</goal>
						</goals>
					</execution>
					<execution>
						<id>test-compile</id>
						<phase>test-compile</phase>
						<goals>
							<goal>test-compile</goal>
						</goals>
					</execution>
				</executions>
				<dependencies>
					<dependency>
						<groupId>org.jetbrains.kotlin</groupId>
						<artifactId>kotlin-maven-allopen</artifactId>
						<version>${kotlin.version}</version>
					</dependency>
				</dependencies>
			</plugin>
		</plugins>
	</build>

</project>

application.properties

spring.thymeleaf.mode= HTML
spring.thymeleaf.cache=false

Project Structure

structures copy

Explanation

Most developers are familiar with the delegation pattern. Delegation provides many of the same benefits as inheritence, but helps reduce issues such as fragile base classes or tight coupling to the base class. Kotlin’s delegation features go further by requiring developers to use an interface which helps promote loose coupling and programming to an interface. Since delegate objects aren’t part of an inheritance chain, we are free to use mutliple objects with delegation.

One of the huge drawbacks of using the delegation pattern in Java is the amount of work involved to use the pattern. Java requires developers to actually declare and implement each method of the delegate object. Although most IDE’s are happy to generate delegate methods, such methods require maintaince later on should an interface add or remove methods. This makes inheritence more attractive since the Java compiler adds or removes methods in child classes as they are added or removed in the base class without additional work from the developer.

The Kotlin compiler address the problems associated with developing delegate objects by generating the delegate methods for the developer. The Kotlin delegation syntax is found in KotlinDelegationApplication.kt on lines 48-51. As mentioned above, Kotlin requires the usage of interfaces when using delegation. This works nicely with Spring Data’s JPA template, since developers simply declare an interface that extends JpaRepository anyway. The delegation pattern is used in the BelchersService class, which takes an instance of BelchersRepository in its constructor and then uses the object to build out delegate methods.

At this point, BelcherService has the same methods as BelcherRepository without the need to generate boilerplate declarations and implementations to the delegate object. Since the code is loosely coupled, we are free to swap out different implementations of BelcherRepository as required. The code is easier to read because we are spared the boilerplate code required to implement the delegation pattern.

You may view the source at https://github.com/archer920/KotlinDelegation

Kotlin Koans—Part 11

This portion of the Kotlin Koans tutorial focuses on Object Expressions. Practically speaking, Object Expressions serve the same role as anonymous innner classes in Java. They let us make modifications on a class in one particular case without having to create an entirely new class.

This portion of the tutorial has developers creating a dynamic Comparator class that sorts numbers in descending order.

fun task10(): List {
    val arrayList = arrayListOf(1, 5, 2)
    Collections.sort(arrayList, object: Comparator {
        override fun compare(o1: Int?, o2: Int?): Int {
            return o2?.compareTo(o1 ?: 0) ?: 0
        }
    })
    return arrayList
}

We could have used a lambda in this case, but that would miss the point of what the tutorial is trying to teach. In this code snippet, the second paramter of Collections.sort is an Object Expression that defines a custom Comparator class.

You’ll notice that the definition of compare is full of null safe expressions as indicated the by ? and ?: opeartors. As a side note, I really like how Kotlin has an arrayListOf() function that let’s you create an ArrayList. Sure it does the same thing as Arrays.asList, but again, it’s more concise.

You can view part 10 here

Kotlin Koans—Part 10

This part of the Kotlin Koans tutorial involved extension functions. This is a construct I have never seen in programming before, so it took me a little bit to get an idea of what it is and when to use this feature.

It seems as if the idea here is to add features to a class without have to use inheritence or some sort of delegate object. Here is the Kotlin code.

//This is the class we are adding to
data class RationalNumber(val numerator: Int, val denominator: Int)

//We are adding an r() method to Int which
//returns an instance of RationalNumber
fun Int.r(): RationalNumber = RationalNumber(toInt(), 1)

//We add an r() method to Pair which returns an
//instance of RationalNumber
fun Pair.r(): RationalNumber = RationalNumber(first, second)

The Kotlin documentation has a motivation section that explains the purpose behind extensions. They explain that in many cases in Java, we end up with FileUtils, StringUtils, *Utils classes. In the ideal world, we would want to add features to say the List class directly rather than having a ListUtils class with a bunch of static methods.

We get something like this in JDK8 with default methods that can get placed in an interface. However, that still requires us to extend and interface to add extra methods. Extensions let us work directly on the classes we are already using.

You can click here to see Part 9

Kotlin Koans—Part 9

Java and Kotlin are strongly typed languages. It’s not necessary to cast types when working up an object graph. For example

public void sort(Collection col){
    //todo
}

sort(new ArrayList());
sort(new HashSet());

This is an example of polymorphism in Java. ArrayList and HashSet are both Collections so it’s acceptable to pass either types to the example sort method.

Keep in mind this is not a two way street. This code would not compile.

public void sort(List list){
    //todo
}

Collection col = new ArrayList();
sort(col); //Compile error!
sort((List) col); //OK

Even though col points at an ArrayList and ArrayList implements List, Java forbids you to pass col to sort without a cast. This is because the compiler has no idea that col is pointing at an ArrayList. Keep in mind this is true of Kotlin also.

Although we can get our code to compile with a cast, it’s still dangerous code. Let’s tweak it a little big and have col point at a HashSet instead of ArrayList.

public void sort(List list){
    //todo
}

Collection col = new HashSet();

//Compiles but throws
//ClassCastException
sort((List) col);

Now the code compiles, but it will fail at run time. There is no way to cast HashSet to a List. HashSet does not implement List in anyway so when the code attempts to make the cast, the code will fail. We have to use the instanceof operator to make sure the cast is safe first.

public void sort(List list){
    //todo
}

Collection col = new HashSet();

if (col instanceof List){
    //Now it's safe
    sort((List) col);
}

This code is now safe. It will check if the runtime type of col is a List first. If the object is a List, it will make the cast. Otherwise, the cast will not get made.

Tutorial

This portion of the Kotlin Koans tutorial shows off how Kotlin handles casting compared to Java. Here is the Java code that needs to get rewrote in Kotlin.

public class JavaCode8 extends JavaCode {
    public int eval(Expr expr) {
        if (expr instanceof Num) {
            return ((Num) expr).getValue();
        }
        if (expr instanceof Sum) {
            Sum sum = (Sum) expr;
            return eval(sum.getLeft()) + eval(sum.getRight());
        }
        throw new IllegalArgumentException("Unknown expression");
    }
}

Kotlin has a when keyword that is used for casting. Here is the equivalent Kotlin code.

fun todoTask8(expr: Expr): Int {
    when (expr) {
        is Num -> return expr.value
        is Sum -> return todoTask8(expr.left) + todoTask8(expr.right)
        else -> throw IllegalArgumentException("Unknown expression")
    }
}

As usual, Kotlin is more concise than Java. The when block starts with the when followed by the variable in question. You can have any number of is clauses in this statement followed by the type. The variable is automatically cast to the specified type on the right hand side of the -> operator.

You can click here to see Part 8

Kotlin Koans—Part 7

This portion of the Kotlin Koans showed off a really boss feature of the language: Data Classes. These are special classes whose primary purpose is to hold data.

Here is a Java class that we start with that’s taken directly from the tutorial.

public class Person {
        private final String name;
        private final int age;

        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        public String getName() {
            return name;
        }

        public int getAge() {
            return age;
        }
    }

It’s not a special class. This is a class with a primary constructor, getters/setters and two private variables. It’s also one of my biggest complaints about the Java language. I can do the same thing in Python like this.

class Person:
    def __init__(self, name=None, age=None):
        self.name = name
        self.age = age

Four lines of code in Python. In all fairness to Java, would could just declare name and age to be public variables, but doing so is not only frowned upon, but many Java libraries look for getter/setter method to access a property of a Java bean. Basically speaking, even though we could allow for public access of a Java property, it’s not really practical at this point.

There is a Java library called Lombok that does a lot to solve this problem.

@Data
public class Person {
    private String name;
    private String age;
}

Lombok has been the solution I have used for most of my projects. It’s not perfect however. For example, I can’t use the @Data annotation to make a read only class. That forces me to use a mix of Lombok annotations or define a stereotype annotation. It’s not a huge problem, but it’s still something to think about.

Kotlin data classes take this to a whole other level. Here is the same class in Kotlin.

data class Person(val name: String, val age: Int)

That’s it! One line of code!!! With this single line of code, we get our two properties, it’s getter methods, hashcode, equals, toString() and a constructor. The class is immutable because the variables are declared with the val keyword. We can make the class mutable by using var instead of val. Finally, we aren’t losing our ability to work with existing Java libaries.

I really don’t see how it can get any better than this. I have used data classes countless times when working with ORM libraries such as hibernate. I’d say 95% of these classes are classes that just hold data and map to a table in the database. Although any IDE can generate constructors, getters/setters, equals, and hashcode, and toString, let’s face it, it’s even better to have this built directly into the language itself.

You can click here to see Part 6