avatarGabriel Shanahan

Summary

The website content provides an in-depth exploration of nullable and generic receiver extensions in Kotlin, offering explanations, examples, and exercises to aid understanding and adoption of these concepts within Java-centric organizations.

Abstract

The article delves into the advanced Kotlin features of nullable and generic receiver extensions. It explains how extension functions can be defined for nullable types and demonstrates the use of generics in extensions to handle various types effectively. The content includes Kotlin Playground examples to illustrate these concepts and clarify common points of confusion, such as the difference between extensions with unbounded versus explicitly bounded generic types. The article emphasizes the importance of understanding these nuances for Kotlin adoption in Java-centric environments and provides practical exercises, including a Kotlin adaptation of real-world Java code. It also acknowledges the support from Etnetera a.s. and encourages readers to join their team.

Opinions

  • The author believes that mastering nullable and generic receiver extensions is crucial for Kotlin adoption, particularly within organizations that primarily use Java.
  • The article suggests that the ability to capture the actual type with generic extensions is a significant advantage over non-generic counterparts.
  • The inclusion of interactive Kotlin Playground examples indicates the author's opinion that hands-on practice is essential for learning and understanding complex programming concepts.
  • The author expresses gratitude to Etnetera a.s. for their support in creating the Kotlin Primer, indicating a positive relationship and potential benefits of collaborative learning within a corporate setting.
  • By providing a Kotlin translation of Java code, the author implies that Kotlin can offer more concise and expressive solutions to existing Java problems.

Nullable & Generic Receivers

Defining extension with nullable and generic receivers, with a common source of confusion explained in the latter. A thorough set of exercises to really get extensions down.

— — — — — — — — — — — — — — —

THE CURRENT VERSION OF THIS ARTICLE IS PUBLISHED HERE.

— — — — — — — — — — — — — — —

Tags: #FUNDAMENTAL CONCEPT #EXERCISE

This article is part of the Kotlin Primer, an opinionated guide to the Kotlin language, which is indented to help facilitate Kotlin adoption inside Java-centric organizations. It was originally written as an organizational learning resource for Etnetera a.s. and I would like to express my sincere gratitude for their support.

It is recommended to read the Introduction before moving on. Check out the Table of Contents for all articles.

In this article, let’s go through some of the ways extensions interact with other Kotlin features, which might not be immediately apparent.

First off — receivers can be nullable:

Extensions can also be combined with generics, to great effect:

In the example above, T is unbounded, which is equivalent to an upper bound of Any?. In other words, this extension is defined on nullable types as well.

To prevent that, you can specify an explicit upper bound:

A common source of confusion with generic receivers is the difference between the following:

At first look, both definitions behave the same and there doesn’t seem to be a clear advantage of using generics at all.

The difference is that the generic variant captures the actual type on which it was called, which allows it to be used e.g. in the return value:

When you don’t actually need to use the type for anything, there is no difference between using a generic parameter and just directly defining the extension on the upper bound of the generic parameter.

Generics Combined With Nullable Receivers

It’s very unlikely that you’ll ever have to think about this, but if you do, you can check this for reference.

Exercises

This is a slightly modified version of Java code I encountered on a real project, some time ago:

public interface ArgSrc {
    /**
     * Retrieves value of specific argument and converts 
     * it to specified type.
     * 
     * @param type type of value created from parameter
     * @param name name of parameter
     * @param index index of parameter
     * @param aux auxiliary parameter for the conversion (may be
     *            null). The interpretation of the auxiliary value
     *            is dependent on particular conversion algorithm
     *            that coerces argument to given type.
     * @param def default value used in situations when no such
     *            parameter exists or the parameter is null.
     * @return    value of specified parameter or def when no value
     *            exists, or value is null.
     */
    <T> T get(Class<T> type, String name, 
              String aux, int index, 
              T def);
}

Go back to What Extension Functions Are Not, jump to the Table of Contents, or continue to Extension Function Applications: Generic Receivers — continued.

Join me in Etnetera
Java
Kotlin
Programming
Object Oriented
Functional Programming
Recommended from ReadMedium