Recent Guides

All About Type Aliases in Kotlin

Have you ever had a conversation like this? Hopefully you haven’t had a conversation like that in real life, but you might have had one like that with your code! For example, take a gander at this: interface RestaurantPatron { fun makeReservation(restaurant: Organization<(Currency, Coupon?) -> Sustenance>) fun visit(restaurant: Organization<(Currency, Coupon?) -> Sustenance>) fun complainAbout(restaurant: Organization<(Currency, Coupon?) -> Sustenance>) } When you see a chunk of code with so many types smushed together, it’s easy to get lost in the details.

Star-Projections and How They Work

Have you ever wondered how star-projections work? Or why they change your function parameter and return types? Or why it seems like sometimes you can actually get by without them? In the first article in this series, An Illustrated Guide to Covariance and Contravariance in Kotlin, we uncovered two simple, easy-to-understand rules that illuminate variance, and saw how they applied to regular class and interface inheritance in Kotlin. In the second article, The Ins and Outs of Generic Variance in Kotlin, we saw how those same two rules played out for generics, discovering what type projections are and how they work.

The Ins and Outs of Generic Variance in Kotlin

Have you ever wondered why generic variance works like it does? Or why Kotlin won’t let you use a type parameter as an argument when it’s marked as out? Have you wondered why the compiler sometimes won’t let you call a certain function on a generic? Yes, generics can seem mysterious, but with just two simple, easy-to-understand rules, we can reason our way through almost everything related to variance.

An Illustrated Guide to Covariance and Contravariance in Kotlin

Generics can often seem confusing. How often have you started to solve a problem with generics, only to realize that they don’t quite work like you thought they did? The good news is that there are some simple, foundational concepts that underpin generic variance. And once you understand those concepts, you won’t have to memorize acronyms or resort to trial-and-error - you’ll simply understand how and why they work!

Getting Real with Kotlin's Reified Type Parameters

Let’s think for a moment about everything that you can do with a class name in Kotlin - think of all the cases where you literally type out the name of a class in your source code. I came up with the following 15 cases, but I probably missed a few. Get your scrolling finger ready, here we go… 1. Define a member property: private val thing: Thing 2.

When (and when not) to Use Type Parameter Constraints in Kotlin

Kotlin allows you to constrain a type parameter on a generic when you declare it, limiting the range of types that it can accept. Why is this helpful? Well, let’s take a look at an example. Let’s say you’ve got a few pets at home, and you want to pick a favorite: fun <T> chooseFavorite(pets: List<T>): T { val favorite = pets[random.nextInt(pets.size)] // This next line won't compile - because `name` can't be resolved println("My favorite pet is ${favorite.

Choosing between with() and run()

In Kotlin’s standard library, the Standard.kt file contains a number of scope functions that put a receiver object into a new scope as either this or as an argument (e.g., it). The with() function tends to be a bit of an outlier. The others are all extension functions, so they’re invoked on an object. with(), on the other hand, takes its receiver (the object that it’s operating upon) as an argument.

Understanding Kotlin's let(), also(), run(), and apply()

Kotlin’s standard library includes some often-used scope functions that are so abstract that even those who have been programming in Kotlin for a while can have a hard time keeping them straight. In this guide, we’re going to clarify four of these scope functions in particular - let(), also(), run(), and apply(). By the end of this guide, you’ll have a framework for understanding them and should have a good idea of which one is most applicable in different scenarios.

Java Optionals and Kotlin Nulls

When Java 8 introduced Streams for operating on collections of data, it also introduced a similar concept, Optional, which has many methods that are similar to Stream, but operates on a single value that might or might not be present. As you migrate your projects from Java to Kotlin, you might come across some Optional objects. What should you do? Should you leave them as Optional, or change them to more idiomatic Kotlin?