Kotlin Inline Classes – How they work and when you should use them

Kotlin Inline Classes – How they work and when you should use them

Kotlin introduced inline classes with version 1.3 as an experimental feature. You should be aware that their implementation can still change in future releases, but it’s already a great time to learn about them now. Inline classes add a simple tool we can use to wrap some other type without adding runtime overhead through additional heap allocations. In this article, we want to see how inline classes in Kotlin work and when it makes sense to use them.

Enable inline classes in your project

To enable inline classes in your project, you simply need to work with Kotlin version > 1.3 which adds the

inline

keyword to the language. Since inline classes are still experimental, your IDE will display related warnings when you make use of them. The warnings can be disabled with explicit compiler flags as described here.

The first glance at inline classes

Inline classes are pretty straightforward. To make a class inlined, you just add the

inline

keyword to your class:


inline class WrappedInt(val value: Int)

Inline classes have some, more or less apparent, restrictions though: It’s required to specify precisely one property in the primary constructor, as shown with

value

. You can’t wrap multiple values in one

inline

class. It is also prohibited to have

init

blocks in inline classes, and you cannot have properties with backing fields. Inline classes can have simple computable properties, however, which we will see later in this article.

At runtime, the wrapped type of an inline class will be used without its wrapper whenever possible. This is similar to Java’s boxed types like

Integer

or

Boolean

, which will be represented as their corresponding primitive type whenever the compiler can do that. That exactly is the great selling point for inline classes in Kotlin: When you inline a class, the class itself won’t be used in the byte code unless it’s absolutely necessary. Inlining classes drastically reduces space overhead at runtime.

Runtime representation

At runtime, an inline class can be represented as both, the wrapper type and the underlying type. As mentioned in the previous paragraph, the compiler prefers using the underlying (wrapped) type of an

inline

class to optimize the code as much as possible. This is similar to boxing between

int

and

Integer

. In certain situations, however, the compiler needs to use the wrapper itself, so it will be generated during compilation:


public final class WrappedInt {
   private final int value;

   public final int getValue() { return this.value; }

   // $FF: synthetic method
   private WrappedInt(int value) { this.value = value; }

   public static int constructor_impl(int value) { return value; }

   // $FF: synthetic method
   @NotNull
   public static final WrappedInt box_impl(int v) { return new WrappedInt(v); }

   // $FF: synthetic method
   public final int unbox_impl() { return this.value; }

   //more Object related implementations
}

This snippet shows the simplified byte code represented as Java code to show how an

inline

class looks like. Along with some obvious stuff like the

value

field and its getter, the constructor is private, and new objects will rather be created through

constructor_impl

which does not actually use the wrapper type but only returns the passed in underlying type. Finally, you can see

box_impl

and

unbox_impl

functions which, as you might expect, are used for boxing purposes. Now let’s see how this inline class wrapper gets utilized when we use the

inline

class in our code.

Using inline classes


fun take(w: WrappedInt) {
    println(w.value)
}

fun main() {
    val inlined = WrappedInt(5)
    take(inlined)
}

In this snippet, a

WrappedInt

is being created and passed to a function which prints its wrapped value. The corresponding byte code, again as Java code, looks as follows:


public static final void take_hqTGqkw(int w) {
    System.out.println(w);
}

public static final void main() {
    int inlined = WrappedInt.constructor_impl(5);
    take_hqTGqkw(inlined);
}

In the compiled code, no instance of

WrappedInt

is created. Although the static

constructor_impl

is used, it just returns an

int

which is then passed to the

take

function that also does not know anything about the type of the

inline

class which we originally had in our source code.
Note that the names of functions accepting inline class parameters are extended with a generated hash code in the byte code. This way, they can stay distinguishable from overloaded functions accepting the underlying type as a parameter:


fun take(w: WrappedInt) = println(w.value)
fun take(v: Int) = println(v.value)

To make both

take

methods available in the JVM byte code and avoid signature clashes, the compiler renames the first one to something like

take-hqTGqkw

. Note that the example above does show a ”

_

” rather than a ”

-

” since Java does not allow method names to contain the dash which is also the reason why methods accepting inline classes are not callable from Java.

Boxing of inline classes

We saw earlier that

box_impl

and

unbox_impl

functions are created for inline classes, so when do we need them? The Kotlin docs cite a rule of thumb which says:

Inline classes are boxed whenever they are used as another type.

Boxing happens, for instance, when you use your inline class as a generic type or a nullable type:


inline class WrappedInt(val value: Int)

fun take(w: WrappedInt?) {
    if (w != null) println(w.value)
}

fun main() {
    take(WrappedInt(5))
}

In this code we modified the

take

function to take a nullable

WrappedInt

and print the underlying type if the argument is not null.


public static final void take_G1XIRLQ(@Nullable WrappedInt w) {
    if (Intrinsics.areEqual(w, (Object)null) ^ true) {
        int var1 = w.unbox_impl();
        System.out.println(var1);
    }
}

public static final void main() {
    take_G1XIRLQ(WrappedInt.box_impl(WrappedInt.constructor_impl(5)));
}

In the byte code,

take

now does not accept the underlying type directly anymore. It has to work with the wrapper type instead. When printing its content,

unbox_impl

is invoked. On the caller site, we can see that

box_impl

is used to create a boxed instance of

WrappedInt

.

It should be evident that we want to avoid boxing whenever possible. Keep in mind that specific usages of inline classes and also primitive types, in general, rely on this technique and might have to be reconsidered.

Use Cases inline classes

We saw that inline classes have a huge advantage: In the best case, they reduce runtime overhead drastically since additional heap allocations are avoided. But when do we want to use wrapper types anyway?

Better typing with inline classes

Imagine an authentication method in an API that looks as follows:


fun auth(userName: String, password: String) { println("authenticating $userName.") }

In a good world, everybody would call it with a user name and their password. However, it is not far-fetched that certain users will invoke this method differently:


auth("12345", "user1")

Since both parameters are of type

String

, you may mess up their order which gets even more likely with an increasing number of arguments of course. Wrappers around these types can help you mitigate that risk, and therefore inline classes are an awesome tool:


inline class Password(val value: String)
inline class UserName(val value: String)

fun auth(userName: UserName, password: Password) { println("authenticating $userName.")}

fun main() {
    auth(UserName("user1"), Password("12345"))
    //does not compile due to type mismatch
    auth(Password("12345"), UserName("user1"))
}

The parameter list has become less confusing and, on the caller site, the compiler will not allow a mismatch. The previously described is probably the most common scenario for using inline classes. They give you simple, type-safe wrappers without introducing additional heap allocations. For these situations, inline classes should be preferred whenever possible. Nevertheless, inline classes can be even smarter, which the next use case demonstrates.

Handling state without additional space

Let’s consider a method that takes a numeric string and parses it into a

BigDecimal

while also adjusting its scale:


/**
 * parses string number into BigDecimal with a scale of 2
 */
fun parseNumber(number: String): BigDecimal {
    return number.toBigDecimal().setScale(2, RoundingMode.HALF_UP)
}

fun main() {
    println(parseNumber("100.12212"))
}

The code is pretty straightforward and would work just fine, but a requirement could be that you need to keep somehow track of the original string that was used to parse the number. To solve that, you would probably create a wrapper type or maybe use the existing

Pair

class to return a pair of values from that function. Those approaches would be valid although it obviously allocates additional space, which, in particular situation, should be avoided.
Inline classes can help you with that. We already noticed that inline classes can’t have multiple properties with backing fields. However, they can have simple calculated members in the form of properties and functions. We can create an inline class for our use case that wraps the original

String

and provides a method or a property that, on demand, parses our value. For the user, this will look like a normal data wrapper around two types while it does not add any runtime overhead in the best case:


inline class ParsableNumber(val original: String) {
    val parsed: BigDecimal
        get() = original.toBigDecimal().setScale(2, RoundingMode.HALF_UP)
}

fun getParsableNumber(number: String): ParsableNumber {
    return ParsableNumber(number)
}

fun main() {
    val parsableNumber = getParsableNumber("100.12212")
    println(parsableNumber.parsed)
    println(parsableNumber.original)
}

As you can see, the

getParsableNumber

method returns an instance of our

inline

class which provides two properties

original

(the underlying type) and

parsed

(the calculated parsed number). That’s an interesting use case that is worth observing on a byte code level again:

More byte code


public final class ParsableNumber {
   @NotNull
   private final String original;

   @NotNull
   public final String getOriginal() { return this.original; }

   // $FF: synthetic method
   private ParsableNumber(@NotNull String original) {
      Intrinsics.checkParameterIsNotNull(original, "original");
      super();
      this.original = original;
   }

   @NotNull
   public static final BigDecimal getParsed_impl(String $this) {
      BigDecimal var10000 = (new BigDecimal($this)).setScale(2, RoundingMode.HALF_UP);
      Intrinsics.checkExpressionValueIsNotNull(var10000, "original.toBigDecimal().…(2, RoundingMode.HALF_UP)");
      return var10000;
   }

   @NotNull
   public static String constructor_impl(@NotNull String original) {
      Intrinsics.checkParameterIsNotNull(original, "original");
      return original;
   }

   // $FF: synthetic method
   @NotNull
   public static final ParsableNumber box_impl(@NotNull String v) {
      Intrinsics.checkParameterIsNotNull(v, "v");
      return new ParsableNumber(v);
   }

   // $FF: synthetic method
   @NotNull
   public final String unbox_impl() { return this.original; }

    //more Object related implementations
}

The generated wrapper class

ParsableNumber

pretty much looks like the earlier shown

WrappedInt

class. One important difference, however, is the

getParsed_impl

function, which represents our computable property

parsed

. As you can see, the function is implemented as a static function that takes a string and returns a

BigDecimal

. So how is this being utilized in the caller code?


@NotNull
public static final String getParsableNumber(@NotNull String number) {
    Intrinsics.checkParameterIsNotNull(number, "number");
    return ParsableNumber.constructor_impl(number);
}

public static final void main() {
    String parsableNumber = getParsableNumber("100.12212");
    BigDecimal var1 = ParsableNumber.getParsed_impl(parsableNumber);
    System.out.println(var1);
    System.out.println(parsableNumber);
}

As expected,

getParsableNumber

does not have any reference to our wrapper type. It simply returns the

String

without introducing any new type. In the

main

, we see that the static

getParsed_impl

is used to parse the given

String

into a

BigDecimal

. Again, no usage of

ParsableNumber

.

Reducing the scope of extension functions

A common issue with extension functions is that they may pollute your namespace if defined on general types like

String

. As an example, you may want to have an extension function that converts a JSON string into a corresponding type:


inline fun <reified T> String.asJson() = jacksonObjectMapper().readValue<T>(this)

To convert a given string into some data holder

JsonData

, you would then do:


val jsonString = """{ "x":200, "y":300 }"""
val data: JsonData = jsonString.asJson()

However, the extension function is available on strings that represent other data as well although it might not make much sense:


"whatever".asJson<JsonData> //will fail

This code will fail since the

String

does not contain valid JSON data. What can we do to make the extension shown above only available for certain strings? Yep, inline classes can help with that:

Narrow down extension scope with inline class


inline class JsonString(val value: String)
inline fun <reified T> JsonString.asJson() = jacksonObjectMapper().readValue<T>(this.value)

When we introduce a wrapper for strings that holds JSON data and change the extension to using a

JsonString

receiver accordingly, the issue described above has been solved. The extension won’t anymore appear on any arbitrary

String

but only those we consciously wrapped in a

JsonString

.

Unsigned Types

Another great use case of inline classes becomes apparent when looking at the unsigned integer types that were added to the language with version 1.3, also as an experimental feature:


public inline class UInt @PublishedApi internal constructor(@PublishedApi internal val data: Int) : Comparable<UInt>

As you can see, the

UInt

class is defined as an unsigned class that wraps a normal signed integer

data

. You can learn more about this feature in the corresponding KEEP.

Conclusion

Inline classes are a great tool that can be used to reduce heap allocations for wrapper types and helps us with solving different kinds of problems. However, be aware that certain scenarios such as using inline classes as nullable types require boxing. Since inline classes are still experimental, you have to expect your code to break in future releases due to changes in their behavior. Please keep this in mind. Nevertheless, I think it’s valid to start using them right away.

If you want to learn more about Kotlin’s beautiful features I recommend the book Kotlin in Action to you and also like to direct you to my other articles 🙂

Another great article about inline classes can be found here (by Dave Leeds).

The post Kotlin Inline Classes – How they work and when you should use them appeared first on Kotlin Expertise Blog.

Continue Reading Kotlin Inline Classes – How they work and when you should use them

Kotlin Inline Classes – How they work and when you should use them

Kotlin Inline Classes – How they work and when you should use them

Kotlin introduced inline classes with version 1.3 as an experimental feature. You should be aware that their implementation can still change in future releases, but it’s already a great time to learn about them now. Inline classes add a simple tool we can use to wrap some other type without adding runtime overhead through additional heap allocations. In this article, we want to see how inline classes in Kotlin work and when it makes sense to use them.

Enable inline classes in your project

To enable inline classes in your project, you simply need to work with Kotlin version > 1.3 which adds the

inline

keyword to the language. Since inline classes are still experimental, your IDE will display related warnings when you make use of them. The warnings can be disabled with explicit compiler flags as described here.

The first glance at inline classes

Inline classes are pretty straightforward. To make a class inlined, you just add the

inline

keyword to your class:


inline class WrappedInt(val value: Int)

Inline classes have some, more or less apparent, restrictions though: It’s required to specify precisely one property in the primary constructor, as shown with

value

. You can’t wrap multiple values in one

inline

class. It is also prohibited to have

init

blocks in inline classes, and you cannot have properties with backing fields. Inline classes can have simple computable properties, however, which we will see later in this article.

At runtime, the wrapped type of an inline class will be used without its wrapper whenever possible. This is similar to Java’s boxed types like

Integer

or

Boolean

, which will be represented as their corresponding primitive type whenever the compiler can do that. That exactly is the great selling point for inline classes in Kotlin: When you inline a class, the class itself won’t be used in the byte code unless it’s absolutely necessary. Inlining classes drastically reduces space overhead at runtime.

Runtime representation

At runtime, an inline class can be represented as both, the wrapper type and the underlying type. As mentioned in the previous paragraph, the compiler prefers using the underlying (wrapped) type of an

inline

class to optimize the code as much as possible. This is similar to boxing between

int

and

Integer

. In certain situations, however, the compiler needs to use the wrapper itself, so it will be generated during compilation:


public final class WrappedInt {
   private final int value;

   public final int getValue() { return this.value; }

   // $FF: synthetic method
   private WrappedInt(int value) { this.value = value; }

   public static int constructor_impl(int value) { return value; }

   // $FF: synthetic method
   @NotNull
   public static final WrappedInt box_impl(int v) { return new WrappedInt(v); }

   // $FF: synthetic method
   public final int unbox_impl() { return this.value; }

   //more Object related implementations
}

This snippet shows the simplified byte code represented as Java code to show how an

inline

class looks like. Along with some obvious stuff like the

value

field and its getter, the constructor is private, and new objects will rather be created through

constructor_impl

which does not actually use the wrapper type but only returns the passed in underlying type. Finally, you can see

box_impl

and

unbox_impl

functions which, as you might expect, are used for boxing purposes. Now let’s see how this inline class wrapper gets utilized when we use the

inline

class in our code.

Using inline classes


fun take(w: WrappedInt) {
    println(w.value)
}

fun main() {
    val inlined = WrappedInt(5)
    take(inlined)
}

In this snippet, a

WrappedInt

is being created and passed to a function which prints its wrapped value. The corresponding byte code, again as Java code, looks as follows:


public static final void take_hqTGqkw(int w) {
    System.out.println(w);
}

public static final void main() {
    int inlined = WrappedInt.constructor_impl(5);
    take_hqTGqkw(inlined);
}

In the compiled code, no instance of

WrappedInt

is created. Although the static

constructor_impl

is used, it just returns an

int

which is then passed to the

take

function that also does not know anything about the type of the

inline

class which we originally had in our source code.
Note that the names of functions accepting inline class parameters are extended with a generated hash code in the byte code. This way, they can stay distinguishable from overloaded functions accepting the underlying type as a parameter:


fun take(w: WrappedInt) = println(w.value)
fun take(v: Int) = println(v.value)

To make both

take

methods available in the JVM byte code and avoid signature clashes, the compiler renames the first one to something like

take-hqTGqkw

. Note that the example above does show a ”

_

” rather than a ”

-

” since Java does not allow method names to contain the dash which is also the reason why methods accepting inline classes are not callable from Java.

Boxing of inline classes

We saw earlier that

box_impl

and

unbox_impl

functions are created for inline classes, so when do we need them? The Kotlin docs cite a rule of thumb which says:

Inline classes are boxed whenever they are used as another type.

Boxing happens, for instance, when you use your inline class as a generic type or a nullable type:


inline class WrappedInt(val value: Int)

fun take(w: WrappedInt?) {
    if (w != null) println(w.value)
}

fun main() {
    take(WrappedInt(5))
}

In this code we modified the

take

function to take a nullable

WrappedInt

and print the underlying type if the argument is not null.


public static final void take_G1XIRLQ(@Nullable WrappedInt w) {
    if (Intrinsics.areEqual(w, (Object)null) ^ true) {
        int var1 = w.unbox_impl();
        System.out.println(var1);
    }
}

public static final void main() {
    take_G1XIRLQ(WrappedInt.box_impl(WrappedInt.constructor_impl(5)));
}

In the byte code,

take

now does not accept the underlying type directly anymore. It has to work with the wrapper type instead. When printing its content,

unbox_impl

is invoked. On the caller site, we can see that

box_impl

is used to create a boxed instance of

WrappedInt

.

It should be evident that we want to avoid boxing whenever possible. Keep in mind that specific usages of inline classes and also primitive types, in general, rely on this technique and might have to be reconsidered.

Use Cases inline classes

We saw that inline classes have a huge advantage: In the best case, they reduce runtime overhead drastically since additional heap allocations are avoided. But when do we want to use wrapper types anyway?

Better typing with inline classes

Imagine an authentication method in an API that looks as follows:


fun auth(userName: String, password: String) { println("authenticating $userName.") }

In a good world, everybody would call it with a user name and their password. However, it is not far-fetched that certain users will invoke this method differently:


auth("12345", "user1")

Since both parameters are of type

String

, you may mess up their order which gets even more likely with an increasing number of arguments of course. Wrappers around these types can help you mitigate that risk, and therefore inline classes are an awesome tool:


inline class Password(val value: String)
inline class UserName(val value: String)

fun auth(userName: UserName, password: Password) { println("authenticating $userName.")}

fun main() {
    auth(UserName("user1"), Password("12345"))
    //does not compile due to type mismatch
    auth(Password("12345"), UserName("user1"))
}

The parameter list has become less confusing and, on the caller site, the compiler will not allow a mismatch. The previously described is probably the most common scenario for using inline classes. They give you simple, type-safe wrappers without introducing additional heap allocations. For these situations, inline classes should be preferred whenever possible. Nevertheless, inline classes can be even smarter, which the next use case demonstrates.

Handling state without additional space

Let’s consider a method that takes a numeric string and parses it into a

BigDecimal

while also adjusting its scale:


/**
 * parses string number into BigDecimal with a scale of 2
 */
fun parseNumber(number: String): BigDecimal {
    return number.toBigDecimal().setScale(2, RoundingMode.HALF_UP)
}

fun main() {
    println(parseNumber("100.12212"))
}

The code is pretty straightforward and would work just fine, but a requirement could be that you need to keep somehow track of the original string that was used to parse the number. To solve that, you would probably create a wrapper type or maybe use the existing

Pair

class to return a pair of values from that function. Those approaches would be valid although it obviously allocates additional space, which, in particular situation, should be avoided.
Inline classes can help you with that. We already noticed that inline classes can’t have multiple properties with backing fields. However, they can have simple calculated members in the form of properties and functions. We can create an inline class for our use case that wraps the original

String

and provides a method or a property that, on demand, parses our value. For the user, this will look like a normal data wrapper around two types while it does not add any runtime overhead in the best case:


inline class ParsableNumber(val original: String) {
    val parsed: BigDecimal
        get() = original.toBigDecimal().setScale(2, RoundingMode.HALF_UP)
}

fun getParsableNumber(number: String): ParsableNumber {
    return ParsableNumber(number)
}

fun main() {
    val parsableNumber = getParsableNumber("100.12212")
    println(parsableNumber.parsed)
    println(parsableNumber.original)
}

As you can see, the

getParsableNumber

method returns an instance of our

inline

class which provides two properties

original

(the underlying type) and

parsed

(the calculated parsed number). That’s an interesting use case that is worth observing on a byte code level again:

More byte code


public final class ParsableNumber {
   @NotNull
   private final String original;

   @NotNull
   public final String getOriginal() { return this.original; }

   // $FF: synthetic method
   private ParsableNumber(@NotNull String original) {
      Intrinsics.checkParameterIsNotNull(original, "original");
      super();
      this.original = original;
   }

   @NotNull
   public static final BigDecimal getParsed_impl(String $this) {
      BigDecimal var10000 = (new BigDecimal($this)).setScale(2, RoundingMode.HALF_UP);
      Intrinsics.checkExpressionValueIsNotNull(var10000, "original.toBigDecimal().…(2, RoundingMode.HALF_UP)");
      return var10000;
   }

   @NotNull
   public static String constructor_impl(@NotNull String original) {
      Intrinsics.checkParameterIsNotNull(original, "original");
      return original;
   }

   // $FF: synthetic method
   @NotNull
   public static final ParsableNumber box_impl(@NotNull String v) {
      Intrinsics.checkParameterIsNotNull(v, "v");
      return new ParsableNumber(v);
   }

   // $FF: synthetic method
   @NotNull
   public final String unbox_impl() { return this.original; }

    //more Object related implementations
}

The generated wrapper class

ParsableNumber

pretty much looks like the earlier shown

WrappedInt

class. One important difference, however, is the

getParsed_impl

function, which represents our computable property

parsed

. As you can see, the function is implemented as a static function that takes a string and returns a

BigDecimal

. So how is this being utilized in the caller code?


@NotNull
public static final String getParsableNumber(@NotNull String number) {
    Intrinsics.checkParameterIsNotNull(number, "number");
    return ParsableNumber.constructor_impl(number);
}

public static final void main() {
    String parsableNumber = getParsableNumber("100.12212");
    BigDecimal var1 = ParsableNumber.getParsed_impl(parsableNumber);
    System.out.println(var1);
    System.out.println(parsableNumber);
}

As expected,

getParsableNumber

does not have any reference to our wrapper type. It simply returns the

String

without introducing any new type. In the

main

, we see that the static

getParsed_impl

is used to parse the given

String

into a

BigDecimal

. Again, no usage of

ParsableNumber

.

Reducing the scope of extension functions

A common issue with extension functions is that they may pollute your namespace if defined on general types like

String

. As an example, you may want to have an extension function that converts a JSON string into a corresponding type:


inline fun <reified T> String.asJson() = jacksonObjectMapper().readValue<T>(this)

To convert a given string into some data holder

JsonData

, you would then do:


val jsonString = """{ "x":200, "y":300 }"""
val data: JsonData = jsonString.asJson()

However, the extension function is available on strings that represent other data as well although it might not make much sense:


"whatever".asJson<JsonData> //will fail

This code will fail since the

String

does not contain valid JSON data. What can we do to make the extension shown above only available for certain strings? Yep, inline classes can help with that:

Narrow down extension scope with inline class


inline class JsonString(val value: String)
inline fun <reified T> JsonString.asJson() = jacksonObjectMapper().readValue<T>(this.value)

When we introduce a wrapper for strings that holds JSON data and change the extension to using a

JsonString

receiver accordingly, the issue described above has been solved. The extension won’t anymore appear on any arbitrary

String

but only those we consciously wrapped in a

JsonString

.

Unsigned Types

Another great use case of inline classes becomes apparent when looking at the unsigned integer types that were added to the language with version 1.3, also as an experimental feature:


public inline class UInt @PublishedApi internal constructor(@PublishedApi internal val data: Int) : Comparable<UInt>

As you can see, the

UInt

class is defined as an unsigned class that wraps a normal signed integer

data

. You can learn more about this feature in the corresponding KEEP.

Conclusion

Inline classes are a great tool that can be used to reduce heap allocations for wrapper types and helps us with solving different kinds of problems. However, be aware that certain scenarios such as using inline classes as nullable types require boxing. Since inline classes are still experimental, you have to expect your code to break in future releases due to changes in their behavior. Please keep this in mind. Nevertheless, I think it’s valid to start using them right away.

If you want to learn more about Kotlin’s beautiful features I recommend the book Kotlin in Action to you and also like to direct you to my other articles 🙂

Another great article about inline classes can be found here (by Dave Leeds).

The post Kotlin Inline Classes – How they work and when you should use them appeared first on Kotlin Expertise Blog.

Continue Reading Kotlin Inline Classes – How they work and when you should use them

Kotlin Inline Classes – How they work and when you should use them

Kotlin Inline Classes – How they work and when you should use them

Kotlin introduced inline classes with version 1.3 as an experimental feature. You should be aware that their implementation can still change in future releases, but it’s already a great time to learn about them now. Inline classes add a simple tool we can use to wrap some other type without adding runtime overhead through additional heap allocations. In this article, we want to see how inline classes in Kotlin work and when it makes sense to use them.

Enable inline classes in your project

To enable inline classes in your project, you simply need to work with Kotlin version > 1.3 which adds the

inline

keyword to the language. Since inline classes are still experimental, your IDE will display related warnings when you make use of them. The warnings can be disabled with explicit compiler flags as described here.

The first glance at inline classes

Inline classes are pretty straightforward. To make a class inlined, you just add the

inline

keyword to your class:


inline class WrappedInt(val value: Int)

Inline classes have some, more or less apparent, restrictions though: It’s required to specify precisely one property in the primary constructor, as shown with

value

. You can’t wrap multiple values in one

inline

class. It is also prohibited to have

init

blocks in inline classes, and you cannot have properties with backing fields. Inline classes can have simple computable properties, however, which we will see later in this article.

At runtime, the wrapped type of an inline class will be used without its wrapper whenever possible. This is similar to Java’s boxed types like

Integer

or

Boolean

, which will be represented as their corresponding primitive type whenever the compiler can do that. That exactly is the great selling point for inline classes in Kotlin: When you inline a class, the class itself won’t be used in the byte code unless it’s absolutely necessary. Inlining classes drastically reduces space overhead at runtime.

Runtime representation

At runtime, an inline class can be represented as both, the wrapper type and the underlying type. As mentioned in the previous paragraph, the compiler prefers using the underlying (wrapped) type of an

inline

class to optimize the code as much as possible. This is similar to boxing between

int

and

Integer

. In certain situations, however, the compiler needs to use the wrapper itself, so it will be generated during compilation:


public final class WrappedInt {
   private final int value;

   public final int getValue() { return this.value; }

   // $FF: synthetic method
   private WrappedInt(int value) { this.value = value; }

   public static int constructor_impl(int value) { return value; }

   // $FF: synthetic method
   @NotNull
   public static final WrappedInt box_impl(int v) { return new WrappedInt(v); }

   // $FF: synthetic method
   public final int unbox_impl() { return this.value; }

   //more Object related implementations
}

This snippet shows the simplified byte code represented as Java code to show how an

inline

class looks like. Along with some obvious stuff like the

value

field and its getter, the constructor is private, and new objects will rather be created through

constructor_impl

which does not actually use the wrapper type but only returns the passed in underlying type. Finally, you can see

box_impl

and

unbox_impl

functions which, as you might expect, are used for boxing purposes. Now let’s see how this inline class wrapper gets utilized when we use the

inline

class in our code.

Using inline classes


fun take(w: WrappedInt) {
    println(w.value)
}

fun main() {
    val inlined = WrappedInt(5)
    take(inlined)
}

In this snippet, a

WrappedInt

is being created and passed to a function which prints its wrapped value. The corresponding byte code, again as Java code, looks as follows:


public static final void take_hqTGqkw(int w) {
    System.out.println(w);
}

public static final void main() {
    int inlined = WrappedInt.constructor_impl(5);
    take_hqTGqkw(inlined);
}

In the compiled code, no instance of

WrappedInt

is created. Although the static

constructor_impl

is used, it just returns an

int

which is then passed to the

take

function that also does not know anything about the type of the

inline

class which we originally had in our source code.
Note that the names of functions accepting inline class parameters are extended with a generated hash code in the byte code. This way, they can stay distinguishable from overloaded functions accepting the underlying type as a parameter:


fun take(w: WrappedInt) = println(w.value)
fun take(v: Int) = println(v.value)

To make both

take

methods available in the JVM byte code and avoid signature clashes, the compiler renames the first one to something like

take-hqTGqkw

. Note that the example above does show a ”

_

” rather than a ”

-

” since Java does not allow method names to contain the dash which is also the reason why methods accepting inline classes are not callable from Java.

Boxing of inline classes

We saw earlier that

box_impl

and

unbox_impl

functions are created for inline classes, so when do we need them? The Kotlin docs cite a rule of thumb which says:

Inline classes are boxed whenever they are used as another type.

Boxing happens, for instance, when you use your inline class as a generic type or a nullable type:


inline class WrappedInt(val value: Int)

fun take(w: WrappedInt?) {
    if (w != null) println(w.value)
}

fun main() {
    take(WrappedInt(5))
}

In this code we modified the

take

function to take a nullable

WrappedInt

and print the underlying type if the argument is not null.


public static final void take_G1XIRLQ(@Nullable WrappedInt w) {
    if (Intrinsics.areEqual(w, (Object)null) ^ true) {
        int var1 = w.unbox_impl();
        System.out.println(var1);
    }
}

public static final void main() {
    take_G1XIRLQ(WrappedInt.box_impl(WrappedInt.constructor_impl(5)));
}

In the byte code,

take

now does not accept the underlying type directly anymore. It has to work with the wrapper type instead. When printing its content,

unbox_impl

is invoked. On the caller site, we can see that

box_impl

is used to create a boxed instance of

WrappedInt

.

It should be evident that we want to avoid boxing whenever possible. Keep in mind that specific usages of inline classes and also primitive types, in general, rely on this technique and might have to be reconsidered.

Use Cases inline classes

We saw that inline classes have a huge advantage: In the best case, they reduce runtime overhead drastically since additional heap allocations are avoided. But when do we want to use wrapper types anyway?

Better typing with inline classes

Imagine an authentication method in an API that looks as follows:


fun auth(userName: String, password: String) { println("authenticating $userName.") }

In a good world, everybody would call it with a user name and their password. However, it is not far-fetched that certain users will invoke this method differently:


auth("12345", "user1")

Since both parameters are of type

String

, you may mess up their order which gets even more likely with an increasing number of arguments of course. Wrappers around these types can help you mitigate that risk, and therefore inline classes are an awesome tool:


inline class Password(val value: String)
inline class UserName(val value: String)

fun auth(userName: UserName, password: Password) { println("authenticating $userName.")}

fun main() {
    auth(UserName("user1"), Password("12345"))
    //does not compile due to type mismatch
    auth(Password("12345"), UserName("user1"))
}

The parameter list has become less confusing and, on the caller site, the compiler will not allow a mismatch. The previously described is probably the most common scenario for using inline classes. They give you simple, type-safe wrappers without introducing additional heap allocations. For these situations, inline classes should be preferred whenever possible. Nevertheless, inline classes can be even smarter, which the next use case demonstrates.

Handling state without additional space

Let’s consider a method that takes a numeric string and parses it into a

BigDecimal

while also adjusting its scale:


/**
 * parses string number into BigDecimal with a scale of 2
 */
fun parseNumber(number: String): BigDecimal {
    return number.toBigDecimal().setScale(2, RoundingMode.HALF_UP)
}

fun main() {
    println(parseNumber("100.12212"))
}

The code is pretty straightforward and would work just fine, but a requirement could be that you need to keep somehow track of the original string that was used to parse the number. To solve that, you would probably create a wrapper type or maybe use the existing

Pair

class to return a pair of values from that function. Those approaches would be valid although it obviously allocates additional space, which, in particular situation, should be avoided.
Inline classes can help you with that. We already noticed that inline classes can’t have multiple properties with backing fields. However, they can have simple calculated members in the form of properties and functions. We can create an inline class for our use case that wraps the original

String

and provides a method or a property that, on demand, parses our value. For the user, this will look like a normal data wrapper around two types while it does not add any runtime overhead in the best case:


inline class ParsableNumber(val original: String) {
    val parsed: BigDecimal
        get() = original.toBigDecimal().setScale(2, RoundingMode.HALF_UP)
}

fun getParsableNumber(number: String): ParsableNumber {
    return ParsableNumber(number)
}

fun main() {
    val parsableNumber = getParsableNumber("100.12212")
    println(parsableNumber.parsed)
    println(parsableNumber.original)
}

As you can see, the

getParsableNumber

method returns an instance of our

inline

class which provides two properties

original

(the underlying type) and

parsed

(the calculated parsed number). That’s an interesting use case that is worth observing on a byte code level again:

More byte code


public final class ParsableNumber {
   @NotNull
   private final String original;

   @NotNull
   public final String getOriginal() { return this.original; }

   // $FF: synthetic method
   private ParsableNumber(@NotNull String original) {
      Intrinsics.checkParameterIsNotNull(original, "original");
      super();
      this.original = original;
   }

   @NotNull
   public static final BigDecimal getParsed_impl(String $this) {
      BigDecimal var10000 = (new BigDecimal($this)).setScale(2, RoundingMode.HALF_UP);
      Intrinsics.checkExpressionValueIsNotNull(var10000, "original.toBigDecimal().…(2, RoundingMode.HALF_UP)");
      return var10000;
   }

   @NotNull
   public static String constructor_impl(@NotNull String original) {
      Intrinsics.checkParameterIsNotNull(original, "original");
      return original;
   }

   // $FF: synthetic method
   @NotNull
   public static final ParsableNumber box_impl(@NotNull String v) {
      Intrinsics.checkParameterIsNotNull(v, "v");
      return new ParsableNumber(v);
   }

   // $FF: synthetic method
   @NotNull
   public final String unbox_impl() { return this.original; }

    //more Object related implementations
}

The generated wrapper class

ParsableNumber

pretty much looks like the earlier shown

WrappedInt

class. One important difference, however, is the

getParsed_impl

function, which represents our computable property

parsed

. As you can see, the function is implemented as a static function that takes a string and returns a

BigDecimal

. So how is this being utilized in the caller code?


@NotNull
public static final String getParsableNumber(@NotNull String number) {
    Intrinsics.checkParameterIsNotNull(number, "number");
    return ParsableNumber.constructor_impl(number);
}

public static final void main() {
    String parsableNumber = getParsableNumber("100.12212");
    BigDecimal var1 = ParsableNumber.getParsed_impl(parsableNumber);
    System.out.println(var1);
    System.out.println(parsableNumber);
}

As expected,

getParsableNumber

does not have any reference to our wrapper type. It simply returns the

String

without introducing any new type. In the

main

, we see that the static

getParsed_impl

is used to parse the given

String

into a

BigDecimal

. Again, no usage of

ParsableNumber

.

Reducing the scope of extension functions

A common issue with extension functions is that they may pollute your namespace if defined on general types like

String

. As an example, you may want to have an extension function that converts a JSON string into a corresponding type:


inline fun <reified T> String.asJson() = jacksonObjectMapper().readValue<T>(this)

To convert a given string into some data holder

JsonData

, you would then do:


val jsonString = """{ "x":200, "y":300 }"""
val data: JsonData = jsonString.asJson()

However, the extension function is available on strings that represent other data as well although it might not make much sense:


"whatever".asJson<JsonData> //will fail

This code will fail since the

String

does not contain valid JSON data. What can we do to make the extension shown above only available for certain strings? Yep, inline classes can help with that:

Narrow down extension scope with inline class


inline class JsonString(val value: String)
inline fun <reified T> JsonString.asJson() = jacksonObjectMapper().readValue<T>(this.value)

When we introduce a wrapper for strings that holds JSON data and change the extension to using a

JsonString

receiver accordingly, the issue described above has been solved. The extension won’t anymore appear on any arbitrary

String

but only those we consciously wrapped in a

JsonString

.

Unsigned Types

Another great use case of inline classes becomes apparent when looking at the unsigned integer types that were added to the language with version 1.3, also as an experimental feature:


public inline class UInt @PublishedApi internal constructor(@PublishedApi internal val data: Int) : Comparable<UInt>

As you can see, the

UInt

class is defined as an unsigned class that wraps a normal signed integer

data

. You can learn more about this feature in the corresponding KEEP.

Conclusion

Inline classes are a great tool that can be used to reduce heap allocations for wrapper types and helps us with solving different kinds of problems. However, be aware that certain scenarios such as using inline classes as nullable types require boxing. Since inline classes are still experimental, you have to expect your code to break in future releases due to changes in their behavior. Please keep this in mind. Nevertheless, I think it’s valid to start using them right away.

If you want to learn more about Kotlin’s beautiful features I recommend the book Kotlin in Action to you and also like to direct you to my other articles 🙂

Another great article about inline classes can be found here (by Dave Leeds).

The post Kotlin Inline Classes – How they work and when you should use them appeared first on Kotlin Expertise Blog.

Continue Reading Kotlin Inline Classes – How they work and when you should use them

Kotlin Inline Classes – How they work and when you should use them

Kotlin Inline Classes – How they work and when you should use them

Kotlin introduced inline classes with version 1.3 as an experimental feature. You should be aware that their implementation can still change in future releases, but it’s already a great time to learn about them now. Inline classes add a simple tool we can use to wrap some other type without adding runtime overhead through additional heap allocations. In this article, we want to see how inline classes in Kotlin work and when it makes sense to use them.

Enable inline classes in your project

To enable inline classes in your project, you simply need to work with Kotlin version > 1.3 which adds the

inline

keyword to the language. Since inline classes are still experimental, your IDE will display related warnings when you make use of them. The warnings can be disabled with explicit compiler flags as described here.

The first glance at inline classes

Inline classes are pretty straightforward. To make a class inlined, you just add the

inline

keyword to your class:


inline class WrappedInt(val value: Int)

Inline classes have some, more or less apparent, restrictions though: It’s required to specify precisely one property in the primary constructor, as shown with

value

. You can’t wrap multiple values in one

inline

class. It is also prohibited to have

init

blocks in inline classes, and you cannot have properties with backing fields. Inline classes can have simple computable properties, however, which we will see later in this article.

At runtime, the wrapped type of an inline class will be used without its wrapper whenever possible. This is similar to Java’s boxed types like

Integer

or

Boolean

, which will be represented as their corresponding primitive type whenever the compiler can do that. That exactly is the great selling point for inline classes in Kotlin: When you inline a class, the class itself won’t be used in the byte code unless it’s absolutely necessary. Inlining classes drastically reduces space overhead at runtime.

Runtime representation

At runtime, an inline class can be represented as both, the wrapper type and the underlying type. As mentioned in the previous paragraph, the compiler prefers using the underlying (wrapped) type of an

inline

class to optimize the code as much as possible. This is similar to boxing between

int

and

Integer

. In certain situations, however, the compiler needs to use the wrapper itself, so it will be generated during compilation:


public final class WrappedInt {
   private final int value;

   public final int getValue() { return this.value; }

   // $FF: synthetic method
   private WrappedInt(int value) { this.value = value; }

   public static int constructor_impl(int value) { return value; }

   // $FF: synthetic method
   @NotNull
   public static final WrappedInt box_impl(int v) { return new WrappedInt(v); }

   // $FF: synthetic method
   public final int unbox_impl() { return this.value; }

   //more Object related implementations
}

This snippet shows the simplified byte code represented as Java code to show how an

inline

class looks like. Along with some obvious stuff like the

value

field and its getter, the constructor is private, and new objects will rather be created through

constructor_impl

which does not actually use the wrapper type but only returns the passed in underlying type. Finally, you can see

box_impl

and

unbox_impl

functions which, as you might expect, are used for boxing purposes. Now let’s see how this inline class wrapper gets utilized when we use the

inline

class in our code.

Using inline classes


fun take(w: WrappedInt) {
    println(w.value)
}

fun main() {
    val inlined = WrappedInt(5)
    take(inlined)
}

In this snippet, a

WrappedInt

is being created and passed to a function which prints its wrapped value. The corresponding byte code, again as Java code, looks as follows:


public static final void take_hqTGqkw(int w) {
    System.out.println(w);
}

public static final void main() {
    int inlined = WrappedInt.constructor_impl(5);
    take_hqTGqkw(inlined);
}

In the compiled code, no instance of

WrappedInt

is created. Although the static

constructor_impl

is used, it just returns an

int

which is then passed to the

take

function that also does not know anything about the type of the

inline

class which we originally had in our source code.
Note that the names of functions accepting inline class parameters are extended with a generated hash code in the byte code. This way, they can stay distinguishable from overloaded functions accepting the underlying type as a parameter:


fun take(w: WrappedInt) = println(w.value)
fun take(v: Int) = println(v.value)

To make both

take

methods available in the JVM byte code and avoid signature clashes, the compiler renames the first one to something like

take-hqTGqkw

. Note that the example above does show a ”

_

” rather than a ”

-

” since Java does not allow method names to contain the dash which is also the reason why methods accepting inline classes are not callable from Java.

Boxing of inline classes

We saw earlier that

box_impl

and

unbox_impl

functions are created for inline classes, so when do we need them? The Kotlin docs cite a rule of thumb which says:

Inline classes are boxed whenever they are used as another type.

Boxing happens, for instance, when you use your inline class as a generic type or a nullable type:


inline class WrappedInt(val value: Int)

fun take(w: WrappedInt?) {
    if (w != null) println(w.value)
}

fun main() {
    take(WrappedInt(5))
}

In this code we modified the

take

function to take a nullable

WrappedInt

and print the underlying type if the argument is not null.


public static final void take_G1XIRLQ(@Nullable WrappedInt w) {
    if (Intrinsics.areEqual(w, (Object)null) ^ true) {
        int var1 = w.unbox_impl();
        System.out.println(var1);
    }
}

public static final void main() {
    take_G1XIRLQ(WrappedInt.box_impl(WrappedInt.constructor_impl(5)));
}

In the byte code,

take

now does not accept the underlying type directly anymore. It has to work with the wrapper type instead. When printing its content,

unbox_impl

is invoked. On the caller site, we can see that

box_impl

is used to create a boxed instance of

WrappedInt

.

It should be evident that we want to avoid boxing whenever possible. Keep in mind that specific usages of inline classes and also primitive types, in general, rely on this technique and might have to be reconsidered.

Use Cases inline classes

We saw that inline classes have a huge advantage: In the best case, they reduce runtime overhead drastically since additional heap allocations are avoided. But when do we want to use wrapper types anyway?

Better typing with inline classes

Imagine an authentication method in an API that looks as follows:


fun auth(userName: String, password: String) { println("authenticating $userName.") }

In a good world, everybody would call it with a user name and their password. However, it is not far-fetched that certain users will invoke this method differently:


auth("12345", "user1")

Since both parameters are of type

String

, you may mess up their order which gets even more likely with an increasing number of arguments of course. Wrappers around these types can help you mitigate that risk, and therefore inline classes are an awesome tool:


inline class Password(val value: String)
inline class UserName(val value: String)

fun auth(userName: UserName, password: Password) { println("authenticating $userName.")}

fun main() {
    auth(UserName("user1"), Password("12345"))
    //does not compile due to type mismatch
    auth(Password("12345"), UserName("user1"))
}

The parameter list has become less confusing and, on the caller site, the compiler will not allow a mismatch. The previously described is probably the most common scenario for using inline classes. They give you simple, type-safe wrappers without introducing additional heap allocations. For these situations, inline classes should be preferred whenever possible. Nevertheless, inline classes can be even smarter, which the next use case demonstrates.

Handling state without additional space

Let’s consider a method that takes a numeric string and parses it into a

BigDecimal

while also adjusting its scale:


/**
 * parses string number into BigDecimal with a scale of 2
 */
fun parseNumber(number: String): BigDecimal {
    return number.toBigDecimal().setScale(2, RoundingMode.HALF_UP)
}

fun main() {
    println(parseNumber("100.12212"))
}

The code is pretty straightforward and would work just fine, but a requirement could be that you need to keep somehow track of the original string that was used to parse the number. To solve that, you would probably create a wrapper type or maybe use the existing

Pair

class to return a pair of values from that function. Those approaches would be valid although it obviously allocates additional space, which, in particular situation, should be avoided.
Inline classes can help you with that. We already noticed that inline classes can’t have multiple properties with backing fields. However, they can have simple calculated members in the form of properties and functions. We can create an inline class for our use case that wraps the original

String

and provides a method or a property that, on demand, parses our value. For the user, this will look like a normal data wrapper around two types while it does not add any runtime overhead in the best case:


inline class ParsableNumber(val original: String) {
    val parsed: BigDecimal
        get() = original.toBigDecimal().setScale(2, RoundingMode.HALF_UP)
}

fun getParsableNumber(number: String): ParsableNumber {
    return ParsableNumber(number)
}

fun main() {
    val parsableNumber = getParsableNumber("100.12212")
    println(parsableNumber.parsed)
    println(parsableNumber.original)
}

As you can see, the

getParsableNumber

method returns an instance of our

inline

class which provides two properties

original

(the underlying type) and

parsed

(the calculated parsed number). That’s an interesting use case that is worth observing on a byte code level again:

More byte code


public final class ParsableNumber {
   @NotNull
   private final String original;

   @NotNull
   public final String getOriginal() { return this.original; }

   // $FF: synthetic method
   private ParsableNumber(@NotNull String original) {
      Intrinsics.checkParameterIsNotNull(original, "original");
      super();
      this.original = original;
   }

   @NotNull
   public static final BigDecimal getParsed_impl(String $this) {
      BigDecimal var10000 = (new BigDecimal($this)).setScale(2, RoundingMode.HALF_UP);
      Intrinsics.checkExpressionValueIsNotNull(var10000, "original.toBigDecimal().…(2, RoundingMode.HALF_UP)");
      return var10000;
   }

   @NotNull
   public static String constructor_impl(@NotNull String original) {
      Intrinsics.checkParameterIsNotNull(original, "original");
      return original;
   }

   // $FF: synthetic method
   @NotNull
   public static final ParsableNumber box_impl(@NotNull String v) {
      Intrinsics.checkParameterIsNotNull(v, "v");
      return new ParsableNumber(v);
   }

   // $FF: synthetic method
   @NotNull
   public final String unbox_impl() { return this.original; }

    //more Object related implementations
}

The generated wrapper class

ParsableNumber

pretty much looks like the earlier shown

WrappedInt

class. One important difference, however, is the

getParsed_impl

function, which represents our computable property

parsed

. As you can see, the function is implemented as a static function that takes a string and returns a

BigDecimal

. So how is this being utilized in the caller code?


@NotNull
public static final String getParsableNumber(@NotNull String number) {
    Intrinsics.checkParameterIsNotNull(number, "number");
    return ParsableNumber.constructor_impl(number);
}

public static final void main() {
    String parsableNumber = getParsableNumber("100.12212");
    BigDecimal var1 = ParsableNumber.getParsed_impl(parsableNumber);
    System.out.println(var1);
    System.out.println(parsableNumber);
}

As expected,

getParsableNumber

does not have any reference to our wrapper type. It simply returns the

String

without introducing any new type. In the

main

, we see that the static

getParsed_impl

is used to parse the given

String

into a

BigDecimal

. Again, no usage of

ParsableNumber

.

Reducing the scope of extension functions

A common issue with extension functions is that they may pollute your namespace if defined on general types like

String

. As an example, you may want to have an extension function that converts a JSON string into a corresponding type:


inline fun <reified T> String.asJson() = jacksonObjectMapper().readValue<T>(this)

To convert a given string into some data holder

JsonData

, you would then do:


val jsonString = """{ "x":200, "y":300 }"""
val data: JsonData = jsonString.asJson()

However, the extension function is available on strings that represent other data as well although it might not make much sense:


"whatever".asJson<JsonData> //will fail

This code will fail since the

String

does not contain valid JSON data. What can we do to make the extension shown above only available for certain strings? Yep, inline classes can help with that:

Narrow down extension scope with inline class


inline class JsonString(val value: String)
inline fun <reified T> JsonString.asJson() = jacksonObjectMapper().readValue<T>(this.value)

When we introduce a wrapper for strings that holds JSON data and change the extension to using a

JsonString

receiver accordingly, the issue described above has been solved. The extension won’t anymore appear on any arbitrary

String

but only those we consciously wrapped in a

JsonString

.

Unsigned Types

Another great use case of inline classes becomes apparent when looking at the unsigned integer types that were added to the language with version 1.3, also as an experimental feature:


public inline class UInt @PublishedApi internal constructor(@PublishedApi internal val data: Int) : Comparable<UInt>

As you can see, the

UInt

class is defined as an unsigned class that wraps a normal signed integer

data

. You can learn more about this feature in the corresponding KEEP.

Conclusion

Inline classes are a great tool that can be used to reduce heap allocations for wrapper types and helps us with solving different kinds of problems. However, be aware that certain scenarios such as using inline classes as nullable types require boxing. Since inline classes are still experimental, you have to expect your code to break in future releases due to changes in their behavior. Please keep this in mind. Nevertheless, I think it’s valid to start using them right away.

If you want to learn more about Kotlin’s beautiful features I recommend the book Kotlin in Action to you and also like to direct you to my other articles 🙂

Another great article about inline classes can be found here (by Dave Leeds).

The post Kotlin Inline Classes – How they work and when you should use them appeared first on Kotlin Expertise Blog.

Continue Reading Kotlin Inline Classes – How they work and when you should use them

Kotlin Inline Classes – How they work and when you should use them

Kotlin Inline Classes – How they work and when you should use them

Kotlin introduced inline classes with version 1.3 as an experimental feature. You should be aware that their implementation can still change in future releases, but it’s already a great time to learn about them now. Inline classes add a simple tool we can use to wrap some other type without adding runtime overhead through additional heap allocations. In this article, we want to see how inline classes in Kotlin work and when it makes sense to use them.

Enable inline classes in your project

To enable inline classes in your project, you simply need to work with Kotlin version > 1.3 which adds the

inline

keyword to the language. Since inline classes are still experimental, your IDE will display related warnings when you make use of them. The warnings can be disabled with explicit compiler flags as described here.

The first glance at inline classes

Inline classes are pretty straightforward. To make a class inlined, you just add the

inline

keyword to your class:


inline class WrappedInt(val value: Int)

Inline classes have some, more or less apparent, restrictions though: It’s required to specify precisely one property in the primary constructor, as shown with

value

. You can’t wrap multiple values in one

inline

class. It is also prohibited to have

init

blocks in inline classes, and you cannot have properties with backing fields. Inline classes can have simple computable properties, however, which we will see later in this article.

At runtime, the wrapped type of an inline class will be used without its wrapper whenever possible. This is similar to Java’s boxed types like

Integer

or

Boolean

, which will be represented as their corresponding primitive type whenever the compiler can do that. That exactly is the great selling point for inline classes in Kotlin: When you inline a class, the class itself won’t be used in the byte code unless it’s absolutely necessary. Inlining classes drastically reduces space overhead at runtime.

Runtime representation

At runtime, an inline class can be represented as both, the wrapper type and the underlying type. As mentioned in the previous paragraph, the compiler prefers using the underlying (wrapped) type of an

inline

class to optimize the code as much as possible. This is similar to boxing between

int

and

Integer

. In certain situations, however, the compiler needs to use the wrapper itself, so it will be generated during compilation:


public final class WrappedInt {
   private final int value;

   public final int getValue() { return this.value; }

   // $FF: synthetic method
   private WrappedInt(int value) { this.value = value; }

   public static int constructor_impl(int value) { return value; }

   // $FF: synthetic method
   @NotNull
   public static final WrappedInt box_impl(int v) { return new WrappedInt(v); }

   // $FF: synthetic method
   public final int unbox_impl() { return this.value; }

   //more Object related implementations
}

This snippet shows the simplified byte code represented as Java code to show how an

inline

class looks like. Along with some obvious stuff like the

value

field and its getter, the constructor is private, and new objects will rather be created through

constructor_impl

which does not actually use the wrapper type but only returns the passed in underlying type. Finally, you can see

box_impl

and

unbox_impl

functions which, as you might expect, are used for boxing purposes. Now let’s see how this inline class wrapper gets utilized when we use the

inline

class in our code.

Using inline classes


fun take(w: WrappedInt) {
    println(w.value)
}

fun main() {
    val inlined = WrappedInt(5)
    take(inlined)
}

In this snippet, a

WrappedInt

is being created and passed to a function which prints its wrapped value. The corresponding byte code, again as Java code, looks as follows:


public static final void take_hqTGqkw(int w) {
    System.out.println(w);
}

public static final void main() {
    int inlined = WrappedInt.constructor_impl(5);
    take_hqTGqkw(inlined);
}

In the compiled code, no instance of

WrappedInt

is created. Although the static

constructor_impl

is used, it just returns an

int

which is then passed to the

take

function that also does not know anything about the type of the

inline

class which we originally had in our source code.
Note that the names of functions accepting inline class parameters are extended with a generated hash code in the byte code. This way, they can stay distinguishable from overloaded functions accepting the underlying type as a parameter:


fun take(w: WrappedInt) = println(w.value)
fun take(v: Int) = println(v.value)

To make both

take

methods available in the JVM byte code and avoid signature clashes, the compiler renames the first one to something like

take-hqTGqkw

. Note that the example above does show a ”

_

” rather than a ”

-

” since Java does not allow method names to contain the dash which is also the reason why methods accepting inline classes are not callable from Java.

Boxing of inline classes

We saw earlier that

box_impl

and

unbox_impl

functions are created for inline classes, so when do we need them? The Kotlin docs cite a rule of thumb which says:

Inline classes are boxed whenever they are used as another type.

Boxing happens, for instance, when you use your inline class as a generic type or a nullable type:


inline class WrappedInt(val value: Int)

fun take(w: WrappedInt?) {
    if (w != null) println(w.value)
}

fun main() {
    take(WrappedInt(5))
}

In this code we modified the

take

function to take a nullable

WrappedInt

and print the underlying type if the argument is not null.


public static final void take_G1XIRLQ(@Nullable WrappedInt w) {
    if (Intrinsics.areEqual(w, (Object)null) ^ true) {
        int var1 = w.unbox_impl();
        System.out.println(var1);
    }
}

public static final void main() {
    take_G1XIRLQ(WrappedInt.box_impl(WrappedInt.constructor_impl(5)));
}

In the byte code,

take

now does not accept the underlying type directly anymore. It has to work with the wrapper type instead. When printing its content,

unbox_impl

is invoked. On the caller site, we can see that

box_impl

is used to create a boxed instance of

WrappedInt

.

It should be evident that we want to avoid boxing whenever possible. Keep in mind that specific usages of inline classes and also primitive types, in general, rely on this technique and might have to be reconsidered.

Use Cases inline classes

We saw that inline classes have a huge advantage: In the best case, they reduce runtime overhead drastically since additional heap allocations are avoided. But when do we want to use wrapper types anyway?

Better typing with inline classes

Imagine an authentication method in an API that looks as follows:


fun auth(userName: String, password: String) { println("authenticating $userName.") }

In a good world, everybody would call it with a user name and their password. However, it is not far-fetched that certain users will invoke this method differently:


auth("12345", "user1")

Since both parameters are of type

String

, you may mess up their order which gets even more likely with an increasing number of arguments of course. Wrappers around these types can help you mitigate that risk, and therefore inline classes are an awesome tool:


inline class Password(val value: String)
inline class UserName(val value: String)

fun auth(userName: UserName, password: Password) { println("authenticating $userName.")}

fun main() {
    auth(UserName("user1"), Password("12345"))
    //does not compile due to type mismatch
    auth(Password("12345"), UserName("user1"))
}

The parameter list has become less confusing and, on the caller site, the compiler will not allow a mismatch. The previously described is probably the most common scenario for using inline classes. They give you simple, type-safe wrappers without introducing additional heap allocations. For these situations, inline classes should be preferred whenever possible. Nevertheless, inline classes can be even smarter, which the next use case demonstrates.

Handling state without additional space

Let’s consider a method that takes a numeric string and parses it into a

BigDecimal

while also adjusting its scale:


/**
 * parses string number into BigDecimal with a scale of 2
 */
fun parseNumber(number: String): BigDecimal {
    return number.toBigDecimal().setScale(2, RoundingMode.HALF_UP)
}

fun main() {
    println(parseNumber("100.12212"))
}

The code is pretty straightforward and would work just fine, but a requirement could be that you need to keep somehow track of the original string that was used to parse the number. To solve that, you would probably create a wrapper type or maybe use the existing

Pair

class to return a pair of values from that function. Those approaches would be valid although it obviously allocates additional space, which, in particular situation, should be avoided.
Inline classes can help you with that. We already noticed that inline classes can’t have multiple properties with backing fields. However, they can have simple calculated members in the form of properties and functions. We can create an inline class for our use case that wraps the original

String

and provides a method or a property that, on demand, parses our value. For the user, this will look like a normal data wrapper around two types while it does not add any runtime overhead in the best case:


inline class ParsableNumber(val original: String) {
    val parsed: BigDecimal
        get() = original.toBigDecimal().setScale(2, RoundingMode.HALF_UP)
}

fun getParsableNumber(number: String): ParsableNumber {
    return ParsableNumber(number)
}

fun main() {
    val parsableNumber = getParsableNumber("100.12212")
    println(parsableNumber.parsed)
    println(parsableNumber.original)
}

As you can see, the

getParsableNumber

method returns an instance of our

inline

class which provides two properties

original

(the underlying type) and

parsed

(the calculated parsed number). That’s an interesting use case that is worth observing on a byte code level again:

More byte code


public final class ParsableNumber {
   @NotNull
   private final String original;

   @NotNull
   public final String getOriginal() { return this.original; }

   // $FF: synthetic method
   private ParsableNumber(@NotNull String original) {
      Intrinsics.checkParameterIsNotNull(original, "original");
      super();
      this.original = original;
   }

   @NotNull
   public static final BigDecimal getParsed_impl(String $this) {
      BigDecimal var10000 = (new BigDecimal($this)).setScale(2, RoundingMode.HALF_UP);
      Intrinsics.checkExpressionValueIsNotNull(var10000, "original.toBigDecimal().…(2, RoundingMode.HALF_UP)");
      return var10000;
   }

   @NotNull
   public static String constructor_impl(@NotNull String original) {
      Intrinsics.checkParameterIsNotNull(original, "original");
      return original;
   }

   // $FF: synthetic method
   @NotNull
   public static final ParsableNumber box_impl(@NotNull String v) {
      Intrinsics.checkParameterIsNotNull(v, "v");
      return new ParsableNumber(v);
   }

   // $FF: synthetic method
   @NotNull
   public final String unbox_impl() { return this.original; }

    //more Object related implementations
}

The generated wrapper class

ParsableNumber

pretty much looks like the earlier shown

WrappedInt

class. One important difference, however, is the

getParsed_impl

function, which represents our computable property

parsed

. As you can see, the function is implemented as a static function that takes a string and returns a

BigDecimal

. So how is this being utilized in the caller code?


@NotNull
public static final String getParsableNumber(@NotNull String number) {
    Intrinsics.checkParameterIsNotNull(number, "number");
    return ParsableNumber.constructor_impl(number);
}

public static final void main() {
    String parsableNumber = getParsableNumber("100.12212");
    BigDecimal var1 = ParsableNumber.getParsed_impl(parsableNumber);
    System.out.println(var1);
    System.out.println(parsableNumber);
}

As expected,

getParsableNumber

does not have any reference to our wrapper type. It simply returns the

String

without introducing any new type. In the

main

, we see that the static

getParsed_impl

is used to parse the given

String

into a

BigDecimal

. Again, no usage of

ParsableNumber

.

Reducing the scope of extension functions

A common issue with extension functions is that they may pollute your namespace if defined on general types like

String

. As an example, you may want to have an extension function that converts a JSON string into a corresponding type:


inline fun <reified T> String.asJson() = jacksonObjectMapper().readValue<T>(this)

To convert a given string into some data holder

JsonData

, you would then do:


val jsonString = """{ "x":200, "y":300 }"""
val data: JsonData = jsonString.asJson()

However, the extension function is available on strings that represent other data as well although it might not make much sense:


"whatever".asJson<JsonData> //will fail

This code will fail since the

String

does not contain valid JSON data. What can we do to make the extension shown above only available for certain strings? Yep, inline classes can help with that:

Narrow down extension scope with inline class


inline class JsonString(val value: String)
inline fun <reified T> JsonString.asJson() = jacksonObjectMapper().readValue<T>(this.value)

When we introduce a wrapper for strings that holds JSON data and change the extension to using a

JsonString

receiver accordingly, the issue described above has been solved. The extension won’t anymore appear on any arbitrary

String

but only those we consciously wrapped in a

JsonString

.

Unsigned Types

Another great use case of inline classes becomes apparent when looking at the unsigned integer types that were added to the language with version 1.3, also as an experimental feature:


public inline class UInt @PublishedApi internal constructor(@PublishedApi internal val data: Int) : Comparable<UInt>

As you can see, the

UInt

class is defined as an unsigned class that wraps a normal signed integer

data

. You can learn more about this feature in the corresponding KEEP.

Conclusion

Inline classes are a great tool that can be used to reduce heap allocations for wrapper types and helps us with solving different kinds of problems. However, be aware that certain scenarios such as using inline classes as nullable types require boxing. Since inline classes are still experimental, you have to expect your code to break in future releases due to changes in their behavior. Please keep this in mind. Nevertheless, I think it’s valid to start using them right away.

If you want to learn more about Kotlin’s beautiful features I recommend the book Kotlin in Action to you and also like to direct you to my other articles 🙂

Another great article about inline classes can be found here (by Dave Leeds).

The post Kotlin Inline Classes – How they work and when you should use them appeared first on Kotlin Expertise Blog.

Continue Reading Kotlin Inline Classes – How they work and when you should use them

Kotlin Inline Classes – How they work and when you should use them

Kotlin Inline Classes – How they work and when you should use them

Kotlin introduced inline classes with version 1.3 as an experimental feature. You should be aware that their implementation can still change in future releases, but it’s already a great time to learn about them now. Inline classes add a simple tool we can use to wrap some other type without adding runtime overhead through additional heap allocations. In this article, we want to see how inline classes in Kotlin work and when it makes sense to use them.

Enable inline classes in your project

To enable inline classes in your project, you simply need to work with Kotlin version > 1.3 which adds the

inline

keyword to the language. Since inline classes are still experimental, your IDE will display related warnings when you make use of them. The warnings can be disabled with explicit compiler flags as described here.

The first glance at inline classes

Inline classes are pretty straightforward. To make a class inlined, you just add the

inline

keyword to your class:


inline class WrappedInt(val value: Int)

Inline classes have some, more or less apparent, restrictions though: It’s required to specify precisely one property in the primary constructor, as shown with

value

. You can’t wrap multiple values in one

inline

class. It is also prohibited to have

init

blocks in inline classes, and you cannot have properties with backing fields. Inline classes can have simple computable properties, however, which we will see later in this article.

At runtime, the wrapped type of an inline class will be used without its wrapper whenever possible. This is similar to Java’s boxed types like

Integer

or

Boolean

, which will be represented as their corresponding primitive type whenever the compiler can do that. That exactly is the great selling point for inline classes in Kotlin: When you inline a class, the class itself won’t be used in the byte code unless it’s absolutely necessary. Inlining classes drastically reduces space overhead at runtime.

Runtime representation

At runtime, an inline class can be represented as both, the wrapper type and the underlying type. As mentioned in the previous paragraph, the compiler prefers using the underlying (wrapped) type of an

inline

class to optimize the code as much as possible. This is similar to boxing between

int

and

Integer

. In certain situations, however, the compiler needs to use the wrapper itself, so it will be generated during compilation:


public final class WrappedInt {
   private final int value;

   public final int getValue() { return this.value; }

   // $FF: synthetic method
   private WrappedInt(int value) { this.value = value; }

   public static int constructor_impl(int value) { return value; }

   // $FF: synthetic method
   @NotNull
   public static final WrappedInt box_impl(int v) { return new WrappedInt(v); }

   // $FF: synthetic method
   public final int unbox_impl() { return this.value; }

   //more Object related implementations
}

This snippet shows the simplified byte code represented as Java code to show how an

inline

class looks like. Along with some obvious stuff like the

value

field and its getter, the constructor is private, and new objects will rather be created through

constructor_impl

which does not actually use the wrapper type but only returns the passed in underlying type. Finally, you can see

box_impl

and

unbox_impl

functions which, as you might expect, are used for boxing purposes. Now let’s see how this inline class wrapper gets utilized when we use the

inline

class in our code.

Using inline classes


fun take(w: WrappedInt) {
    println(w.value)
}

fun main() {
    val inlined = WrappedInt(5)
    take(inlined)
}

In this snippet, a

WrappedInt

is being created and passed to a function which prints its wrapped value. The corresponding byte code, again as Java code, looks as follows:


public static final void take_hqTGqkw(int w) {
    System.out.println(w);
}

public static final void main() {
    int inlined = WrappedInt.constructor_impl(5);
    take_hqTGqkw(inlined);
}

In the compiled code, no instance of

WrappedInt

is created. Although the static

constructor_impl

is used, it just returns an

int

which is then passed to the

take

function that also does not know anything about the type of the

inline

class which we originally had in our source code.
Note that the names of functions accepting inline class parameters are extended with a generated hash code in the byte code. This way, they can stay distinguishable from overloaded functions accepting the underlying type as a parameter:


fun take(w: WrappedInt) = println(w.value)
fun take(v: Int) = println(v.value)

To make both

take

methods available in the JVM byte code and avoid signature clashes, the compiler renames the first one to something like

take-hqTGqkw

. Note that the example above does show a ”

_

” rather than a ”

-

” since Java does not allow method names to contain the dash which is also the reason why methods accepting inline classes are not callable from Java.

Boxing of inline classes

We saw earlier that

box_impl

and

unbox_impl

functions are created for inline classes, so when do we need them? The Kotlin docs cite a rule of thumb which says:

Inline classes are boxed whenever they are used as another type.

Boxing happens, for instance, when you use your inline class as a generic type or a nullable type:


inline class WrappedInt(val value: Int)

fun take(w: WrappedInt?) {
    if (w != null) println(w.value)
}

fun main() {
    take(WrappedInt(5))
}

In this code we modified the

take

function to take a nullable

WrappedInt

and print the underlying type if the argument is not null.


public static final void take_G1XIRLQ(@Nullable WrappedInt w) {
    if (Intrinsics.areEqual(w, (Object)null) ^ true) {
        int var1 = w.unbox_impl();
        System.out.println(var1);
    }
}

public static final void main() {
    take_G1XIRLQ(WrappedInt.box_impl(WrappedInt.constructor_impl(5)));
}

In the byte code,

take

now does not accept the underlying type directly anymore. It has to work with the wrapper type instead. When printing its content,

unbox_impl

is invoked. On the caller site, we can see that

box_impl

is used to create a boxed instance of

WrappedInt

.

It should be evident that we want to avoid boxing whenever possible. Keep in mind that specific usages of inline classes and also primitive types, in general, rely on this technique and might have to be reconsidered.

Use Cases inline classes

We saw that inline classes have a huge advantage: In the best case, they reduce runtime overhead drastically since additional heap allocations are avoided. But when do we want to use wrapper types anyway?

Better typing with inline classes

Imagine an authentication method in an API that looks as follows:


fun auth(userName: String, password: String) { println("authenticating $userName.") }

In a good world, everybody would call it with a user name and their password. However, it is not far-fetched that certain users will invoke this method differently:


auth("12345", "user1")

Since both parameters are of type

String

, you may mess up their order which gets even more likely with an increasing number of arguments of course. Wrappers around these types can help you mitigate that risk, and therefore inline classes are an awesome tool:


inline class Password(val value: String)
inline class UserName(val value: String)

fun auth(userName: UserName, password: Password) { println("authenticating $userName.")}

fun main() {
    auth(UserName("user1"), Password("12345"))
    //does not compile due to type mismatch
    auth(Password("12345"), UserName("user1"))
}

The parameter list has become less confusing and, on the caller site, the compiler will not allow a mismatch. The previously described is probably the most common scenario for using inline classes. They give you simple, type-safe wrappers without introducing additional heap allocations. For these situations, inline classes should be preferred whenever possible. Nevertheless, inline classes can be even smarter, which the next use case demonstrates.

Handling state without additional space

Let’s consider a method that takes a numeric string and parses it into a

BigDecimal

while also adjusting its scale:


/**
 * parses string number into BigDecimal with a scale of 2
 */
fun parseNumber(number: String): BigDecimal {
    return number.toBigDecimal().setScale(2, RoundingMode.HALF_UP)
}

fun main() {
    println(parseNumber("100.12212"))
}

The code is pretty straightforward and would work just fine, but a requirement could be that you need to keep somehow track of the original string that was used to parse the number. To solve that, you would probably create a wrapper type or maybe use the existing

Pair

class to return a pair of values from that function. Those approaches would be valid although it obviously allocates additional space, which, in particular situation, should be avoided.
Inline classes can help you with that. We already noticed that inline classes can’t have multiple properties with backing fields. However, they can have simple calculated members in the form of properties and functions. We can create an inline class for our use case that wraps the original

String

and provides a method or a property that, on demand, parses our value. For the user, this will look like a normal data wrapper around two types while it does not add any runtime overhead in the best case:


inline class ParsableNumber(val original: String) {
    val parsed: BigDecimal
        get() = original.toBigDecimal().setScale(2, RoundingMode.HALF_UP)
}

fun getParsableNumber(number: String): ParsableNumber {
    return ParsableNumber(number)
}

fun main() {
    val parsableNumber = getParsableNumber("100.12212")
    println(parsableNumber.parsed)
    println(parsableNumber.original)
}

As you can see, the

getParsableNumber

method returns an instance of our

inline

class which provides two properties

original

(the underlying type) and

parsed

(the calculated parsed number). That’s an interesting use case that is worth observing on a byte code level again:

More byte code


public final class ParsableNumber {
   @NotNull
   private final String original;

   @NotNull
   public final String getOriginal() { return this.original; }

   // $FF: synthetic method
   private ParsableNumber(@NotNull String original) {
      Intrinsics.checkParameterIsNotNull(original, "original");
      super();
      this.original = original;
   }

   @NotNull
   public static final BigDecimal getParsed_impl(String $this) {
      BigDecimal var10000 = (new BigDecimal($this)).setScale(2, RoundingMode.HALF_UP);
      Intrinsics.checkExpressionValueIsNotNull(var10000, "original.toBigDecimal().…(2, RoundingMode.HALF_UP)");
      return var10000;
   }

   @NotNull
   public static String constructor_impl(@NotNull String original) {
      Intrinsics.checkParameterIsNotNull(original, "original");
      return original;
   }

   // $FF: synthetic method
   @NotNull
   public static final ParsableNumber box_impl(@NotNull String v) {
      Intrinsics.checkParameterIsNotNull(v, "v");
      return new ParsableNumber(v);
   }

   // $FF: synthetic method
   @NotNull
   public final String unbox_impl() { return this.original; }

    //more Object related implementations
}

The generated wrapper class

ParsableNumber

pretty much looks like the earlier shown

WrappedInt

class. One important difference, however, is the

getParsed_impl

function, which represents our computable property

parsed

. As you can see, the function is implemented as a static function that takes a string and returns a

BigDecimal

. So how is this being utilized in the caller code?


@NotNull
public static final String getParsableNumber(@NotNull String number) {
    Intrinsics.checkParameterIsNotNull(number, "number");
    return ParsableNumber.constructor_impl(number);
}

public static final void main() {
    String parsableNumber = getParsableNumber("100.12212");
    BigDecimal var1 = ParsableNumber.getParsed_impl(parsableNumber);
    System.out.println(var1);
    System.out.println(parsableNumber);
}

As expected,

getParsableNumber

does not have any reference to our wrapper type. It simply returns the

String

without introducing any new type. In the

main

, we see that the static

getParsed_impl

is used to parse the given

String

into a

BigDecimal

. Again, no usage of

ParsableNumber

.

Reducing the scope of extension functions

A common issue with extension functions is that they may pollute your namespace if defined on general types like

String

. As an example, you may want to have an extension function that converts a JSON string into a corresponding type:


inline fun <reified T> String.asJson() = jacksonObjectMapper().readValue<T>(this)

To convert a given string into some data holder

JsonData

, you would then do:


val jsonString = """{ "x":200, "y":300 }"""
val data: JsonData = jsonString.asJson()

However, the extension function is available on strings that represent other data as well although it might not make much sense:


"whatever".asJson<JsonData> //will fail

This code will fail since the

String

does not contain valid JSON data. What can we do to make the extension shown above only available for certain strings? Yep, inline classes can help with that:

Narrow down extension scope with inline class


inline class JsonString(val value: String)
inline fun <reified T> JsonString.asJson() = jacksonObjectMapper().readValue<T>(this.value)

When we introduce a wrapper for strings that holds JSON data and change the extension to using a

JsonString

receiver accordingly, the issue described above has been solved. The extension won’t anymore appear on any arbitrary

String

but only those we consciously wrapped in a

JsonString

.

Unsigned Types

Another great use case of inline classes becomes apparent when looking at the unsigned integer types that were added to the language with version 1.3, also as an experimental feature:


public inline class UInt @PublishedApi internal constructor(@PublishedApi internal val data: Int) : Comparable<UInt>

As you can see, the

UInt

class is defined as an unsigned class that wraps a normal signed integer

data

. You can learn more about this feature in the corresponding KEEP.

Conclusion

Inline classes are a great tool that can be used to reduce heap allocations for wrapper types and helps us with solving different kinds of problems. However, be aware that certain scenarios such as using inline classes as nullable types require boxing. Since inline classes are still experimental, you have to expect your code to break in future releases due to changes in their behavior. Please keep this in mind. Nevertheless, I think it’s valid to start using them right away.

If you want to learn more about Kotlin’s beautiful features I recommend the book Kotlin in Action to you and also like to direct you to my other articles 🙂

Another great article about inline classes can be found here (by Dave Leeds).

The post Kotlin Inline Classes – How they work and when you should use them appeared first on Kotlin Expertise Blog.

Continue Reading Kotlin Inline Classes – How they work and when you should use them

Kotlin Inline Classes – How they work and when you should use them

Kotlin Inline Classes – How they work and when you should use them

Kotlin introduced inline classes with version 1.3 as an experimental feature. You should be aware that their implementation can still change in future releases, but it’s already a great time to learn about them now. Inline classes add a simple tool we can use to wrap some other type without adding runtime overhead through additional heap allocations. In this article, we want to see how inline classes in Kotlin work and when it makes sense to use them.

Enable inline classes in your project

To enable inline classes in your project, you simply need to work with Kotlin version > 1.3 which adds the

inline

keyword to the language. Since inline classes are still experimental, your IDE will display related warnings when you make use of them. The warnings can be disabled with explicit compiler flags as described here.

The first glance at inline classes

Inline classes are pretty straightforward. To make a class inlined, you just add the

inline

keyword to your class:


inline class WrappedInt(val value: Int)

Inline classes have some, more or less apparent, restrictions though: It’s required to specify precisely one property in the primary constructor, as shown with

value

. You can’t wrap multiple values in one

inline

class. It is also prohibited to have

init

blocks in inline classes, and you cannot have properties with backing fields. Inline classes can have simple computable properties, however, which we will see later in this article.

At runtime, the wrapped type of an inline class will be used without its wrapper whenever possible. This is similar to Java’s boxed types like

Integer

or

Boolean

, which will be represented as their corresponding primitive type whenever the compiler can do that. That exactly is the great selling point for inline classes in Kotlin: When you inline a class, the class itself won’t be used in the byte code unless it’s absolutely necessary. Inlining classes drastically reduces space overhead at runtime.

Runtime representation

At runtime, an inline class can be represented as both, the wrapper type and the underlying type. As mentioned in the previous paragraph, the compiler prefers using the underlying (wrapped) type of an

inline

class to optimize the code as much as possible. This is similar to boxing between

int

and

Integer

. In certain situations, however, the compiler needs to use the wrapper itself, so it will be generated during compilation:


public final class WrappedInt {
   private final int value;

   public final int getValue() { return this.value; }

   // $FF: synthetic method
   private WrappedInt(int value) { this.value = value; }

   public static int constructor_impl(int value) { return value; }

   // $FF: synthetic method
   @NotNull
   public static final WrappedInt box_impl(int v) { return new WrappedInt(v); }

   // $FF: synthetic method
   public final int unbox_impl() { return this.value; }

   //more Object related implementations
}

This snippet shows the simplified byte code represented as Java code to show how an

inline

class looks like. Along with some obvious stuff like the

value

field and its getter, the constructor is private, and new objects will rather be created through

constructor_impl

which does not actually use the wrapper type but only returns the passed in underlying type. Finally, you can see

box_impl

and

unbox_impl

functions which, as you might expect, are used for boxing purposes. Now let’s see how this inline class wrapper gets utilized when we use the

inline

class in our code.

Using inline classes


fun take(w: WrappedInt) {
    println(w.value)
}

fun main() {
    val inlined = WrappedInt(5)
    take(inlined)
}

In this snippet, a

WrappedInt

is being created and passed to a function which prints its wrapped value. The corresponding byte code, again as Java code, looks as follows:


public static final void take_hqTGqkw(int w) {
    System.out.println(w);
}

public static final void main() {
    int inlined = WrappedInt.constructor_impl(5);
    take_hqTGqkw(inlined);
}

In the compiled code, no instance of

WrappedInt

is created. Although the static

constructor_impl

is used, it just returns an

int

which is then passed to the

take

function that also does not know anything about the type of the

inline

class which we originally had in our source code.
Note that the names of functions accepting inline class parameters are extended with a generated hash code in the byte code. This way, they can stay distinguishable from overloaded functions accepting the underlying type as a parameter:


fun take(w: WrappedInt) = println(w.value)
fun take(v: Int) = println(v.value)

To make both

take

methods available in the JVM byte code and avoid signature clashes, the compiler renames the first one to something like

take-hqTGqkw

. Note that the example above does show a ”

_

” rather than a ”

-

” since Java does not allow method names to contain the dash which is also the reason why methods accepting inline classes are not callable from Java.

Boxing of inline classes

We saw earlier that

box_impl

and

unbox_impl

functions are created for inline classes, so when do we need them? The Kotlin docs cite a rule of thumb which says:

Inline classes are boxed whenever they are used as another type.

Boxing happens, for instance, when you use your inline class as a generic type or a nullable type:


inline class WrappedInt(val value: Int)

fun take(w: WrappedInt?) {
    if (w != null) println(w.value)
}

fun main() {
    take(WrappedInt(5))
}

In this code we modified the

take

function to take a nullable

WrappedInt

and print the underlying type if the argument is not null.


public static final void take_G1XIRLQ(@Nullable WrappedInt w) {
    if (Intrinsics.areEqual(w, (Object)null) ^ true) {
        int var1 = w.unbox_impl();
        System.out.println(var1);
    }
}

public static final void main() {
    take_G1XIRLQ(WrappedInt.box_impl(WrappedInt.constructor_impl(5)));
}

In the byte code,

take

now does not accept the underlying type directly anymore. It has to work with the wrapper type instead. When printing its content,

unbox_impl

is invoked. On the caller site, we can see that

box_impl

is used to create a boxed instance of

WrappedInt

.

It should be evident that we want to avoid boxing whenever possible. Keep in mind that specific usages of inline classes and also primitive types, in general, rely on this technique and might have to be reconsidered.

Use Cases inline classes

We saw that inline classes have a huge advantage: In the best case, they reduce runtime overhead drastically since additional heap allocations are avoided. But when do we want to use wrapper types anyway?

Better typing with inline classes

Imagine an authentication method in an API that looks as follows:


fun auth(userName: String, password: String) { println("authenticating $userName.") }

In a good world, everybody would call it with a user name and their password. However, it is not far-fetched that certain users will invoke this method differently:


auth("12345", "user1")

Since both parameters are of type

String

, you may mess up their order which gets even more likely with an increasing number of arguments of course. Wrappers around these types can help you mitigate that risk, and therefore inline classes are an awesome tool:


inline class Password(val value: String)
inline class UserName(val value: String)

fun auth(userName: UserName, password: Password) { println("authenticating $userName.")}

fun main() {
    auth(UserName("user1"), Password("12345"))
    //does not compile due to type mismatch
    auth(Password("12345"), UserName("user1"))
}

The parameter list has become less confusing and, on the caller site, the compiler will not allow a mismatch. The previously described is probably the most common scenario for using inline classes. They give you simple, type-safe wrappers without introducing additional heap allocations. For these situations, inline classes should be preferred whenever possible. Nevertheless, inline classes can be even smarter, which the next use case demonstrates.

Handling state without additional space

Let’s consider a method that takes a numeric string and parses it into a

BigDecimal

while also adjusting its scale:


/**
 * parses string number into BigDecimal with a scale of 2
 */
fun parseNumber(number: String): BigDecimal {
    return number.toBigDecimal().setScale(2, RoundingMode.HALF_UP)
}

fun main() {
    println(parseNumber("100.12212"))
}

The code is pretty straightforward and would work just fine, but a requirement could be that you need to keep somehow track of the original string that was used to parse the number. To solve that, you would probably create a wrapper type or maybe use the existing

Pair

class to return a pair of values from that function. Those approaches would be valid although it obviously allocates additional space, which, in particular situation, should be avoided.
Inline classes can help you with that. We already noticed that inline classes can’t have multiple properties with backing fields. However, they can have simple calculated members in the form of properties and functions. We can create an inline class for our use case that wraps the original

String

and provides a method or a property that, on demand, parses our value. For the user, this will look like a normal data wrapper around two types while it does not add any runtime overhead in the best case:


inline class ParsableNumber(val original: String) {
    val parsed: BigDecimal
        get() = original.toBigDecimal().setScale(2, RoundingMode.HALF_UP)
}

fun getParsableNumber(number: String): ParsableNumber {
    return ParsableNumber(number)
}

fun main() {
    val parsableNumber = getParsableNumber("100.12212")
    println(parsableNumber.parsed)
    println(parsableNumber.original)
}

As you can see, the

getParsableNumber

method returns an instance of our

inline

class which provides two properties

original

(the underlying type) and

parsed

(the calculated parsed number). That’s an interesting use case that is worth observing on a byte code level again:

More byte code


public final class ParsableNumber {
   @NotNull
   private final String original;

   @NotNull
   public final String getOriginal() { return this.original; }

   // $FF: synthetic method
   private ParsableNumber(@NotNull String original) {
      Intrinsics.checkParameterIsNotNull(original, "original");
      super();
      this.original = original;
   }

   @NotNull
   public static final BigDecimal getParsed_impl(String $this) {
      BigDecimal var10000 = (new BigDecimal($this)).setScale(2, RoundingMode.HALF_UP);
      Intrinsics.checkExpressionValueIsNotNull(var10000, "original.toBigDecimal().…(2, RoundingMode.HALF_UP)");
      return var10000;
   }

   @NotNull
   public static String constructor_impl(@NotNull String original) {
      Intrinsics.checkParameterIsNotNull(original, "original");
      return original;
   }

   // $FF: synthetic method
   @NotNull
   public static final ParsableNumber box_impl(@NotNull String v) {
      Intrinsics.checkParameterIsNotNull(v, "v");
      return new ParsableNumber(v);
   }

   // $FF: synthetic method
   @NotNull
   public final String unbox_impl() { return this.original; }

    //more Object related implementations
}

The generated wrapper class

ParsableNumber

pretty much looks like the earlier shown

WrappedInt

class. One important difference, however, is the

getParsed_impl

function, which represents our computable property

parsed

. As you can see, the function is implemented as a static function that takes a string and returns a

BigDecimal

. So how is this being utilized in the caller code?


@NotNull
public static final String getParsableNumber(@NotNull String number) {
    Intrinsics.checkParameterIsNotNull(number, "number");
    return ParsableNumber.constructor_impl(number);
}

public static final void main() {
    String parsableNumber = getParsableNumber("100.12212");
    BigDecimal var1 = ParsableNumber.getParsed_impl(parsableNumber);
    System.out.println(var1);
    System.out.println(parsableNumber);
}

As expected,

getParsableNumber

does not have any reference to our wrapper type. It simply returns the

String

without introducing any new type. In the

main

, we see that the static

getParsed_impl

is used to parse the given

String

into a

BigDecimal

. Again, no usage of

ParsableNumber

.

Reducing the scope of extension functions

A common issue with extension functions is that they may pollute your namespace if defined on general types like

String

. As an example, you may want to have an extension function that converts a JSON string into a corresponding type:


inline fun <reified T> String.asJson() = jacksonObjectMapper().readValue<T>(this)

To convert a given string into some data holder

JsonData

, you would then do:


val jsonString = """{ "x":200, "y":300 }"""
val data: JsonData = jsonString.asJson()

However, the extension function is available on strings that represent other data as well although it might not make much sense:


"whatever".asJson<JsonData> //will fail

This code will fail since the

String

does not contain valid JSON data. What can we do to make the extension shown above only available for certain strings? Yep, inline classes can help with that:

Narrow down extension scope with inline class


inline class JsonString(val value: String)
inline fun <reified T> JsonString.asJson() = jacksonObjectMapper().readValue<T>(this.value)

When we introduce a wrapper for strings that holds JSON data and change the extension to using a

JsonString

receiver accordingly, the issue described above has been solved. The extension won’t anymore appear on any arbitrary

String

but only those we consciously wrapped in a

JsonString

.

Unsigned Types

Another great use case of inline classes becomes apparent when looking at the unsigned integer types that were added to the language with version 1.3, also as an experimental feature:


public inline class UInt @PublishedApi internal constructor(@PublishedApi internal val data: Int) : Comparable<UInt>

As you can see, the

UInt

class is defined as an unsigned class that wraps a normal signed integer

data

. You can learn more about this feature in the corresponding KEEP.

Conclusion

Inline classes are a great tool that can be used to reduce heap allocations for wrapper types and helps us with solving different kinds of problems. However, be aware that certain scenarios such as using inline classes as nullable types require boxing. Since inline classes are still experimental, you have to expect your code to break in future releases due to changes in their behavior. Please keep this in mind. Nevertheless, I think it’s valid to start using them right away.

If you want to learn more about Kotlin’s beautiful features I recommend the book Kotlin in Action to you and also like to direct you to my other articles 🙂

Another great article about inline classes can be found here (by Dave Leeds).

The post Kotlin Inline Classes – How they work and when you should use them appeared first on Kotlin Expertise Blog.

Continue Reading Kotlin Inline Classes – How they work and when you should use them

How Kotlin makes me a more productive software developer

How Kotlin makes me a more productive software developer

I’ve been writing JVM code for more than seven years now, and I did so mainly using Java. This changed about two years ago when I picked up Kotlin. By now, I managed to drop the Java language more-or-less entirely in favor of Kotlin. I did this because I feel much more productive with the language. It lets me focus more on the business logic rather than forcing me to write boilerplate code over and over again. In this post, I tell you how Kotlin makes me a more productive developer.
I certainly know Kotlin much better than I ever knew Java. FWIW, I had been certified as a Java expert by Oracle some years back. Still, Kotlin became my native programming language, and I want to encourage you to consider it too. When I talk about my Kotlin productivity, this probably is based on personal sentiment. I’m in a particular situation as I picked up the language rather early, right before 1.0 was released, and also worked as a teacher for the language ever since. Nevertheless, I’m convinced that some of the arguments in favor of Kotlin apply to many more of you, so let’s see what I’m talking about.

My JVM background

I used Java intensively for some years and wrote much productive code with the language. Java was my first language, and I did not know other languages too well at that point. Despite not having seen many other languages, I never really felt much joy when using Java, which changed when Java 8 arrived back in 2014. I immediately fell in love with the functional aspects that were added to the language and used lambdas and streams all over our code base. There might have been some situations in which I shouldn’t have done so, but it was bleeding Java edge, and I loved it. At that time, I started looking into other JVM languages and started to learn Scala at some point. I began by reading its documentation which was fun at first but then quickly started to become scary. I never really gave it a proper chance but looking back, I don’t regret putting it away after only a few weeks.

Kotlin

I don’t quite remember where I heard about Kotlin for the first time. The only thing I do remember is that JetBrains was mentioned along with it. I’ve always been a fan of their products, and so it was clear that I had to investigate the language they created. Other than Scala, Kotlin has a very digestible documentation, and it never got scary when I read it. I remember that I binge-read it in only a few days and there were like two topics I didn’t quite understand directly and bookmarked for later. One of those topics was backing fields, and the other one was probably related to delegation support.
Another thing that made it super easy to pick up Kotlin was the excellent support in IntelliJ. I learned the language with the IDE and the documentation. Another resource I totally recommend is the book Kotlin in Action which also helped me a lot with understanding the inner workings of the language better.

Standard Library

Kotlin has a fantastic standard library. If you think that Java also does, I can assure you that it is much weaker than Kotlin’s. You won’t need external libraries for everyday tasks like checking whether a

String

is blank or copying streams around. Kotlin provides all that and much more. It comes with an extremely sophisticated collections API, defines commonly needed extension functions on default types and finally gives the developer the option to add their own functions via extensions. You can find an excellent article on a bunch of standard functions here for example.

Feature-rich language

This one should be obvious. Especially when you’re coming from a language like Java, you will be blessed by the crisp features Kotlin provides. Think about null-safety, extension functions, easier generics or its catchy concurrency means provided by coroutines for instance – they all make us more productive and make the language more enjoyable.

Kotlin is intuitive

As a result of the fantastic standard library and the rich feature set, Kotlin is a very intuitive language. Frequently, you may try to perform some action on a given type and see what existing functions the IDE suggests. It then often happens that you find the function you were looking for already defined. Examples of this would be String::substringBefore, File::extension or Iterable::toSet.

Functional Style

When we talk about the standard library and also how intuitive the language is by itself, we also want to mention the functional aspects of the language. In this part, I particularly want to focus on functions. As you might already know, functions are first class citizens in Kotlin. You can declare variables holding them, pass them around and even return functions from other functions. You find lambdas (undeclared and directly passed functions) in every Kotlin code base. They are heavily used in the Kotlin standard library too. One example of this is the very helpful set of scope functions, which you can learn about here. Of course, lambdas are a vital ingredient to the collections API, i.e., stuff defined in

kotlin.collections

, as well. I can’t even tell how many times I use these functions in my day to day work. It somewhat gives me the creeps when I think about transforming collections within traditional

for

loops and how difficult it was to perform similar tasks in Java, especially before Java 8. Let’s see an example in action. Let’s assume we have some table/grid data modeled as follows:

Example


data class Grid(val rows: List<Row>)
data class Row(val data: List<Column<*>>)
data class Column<T>(val name: String, val value: T)

A

Grid

has multiple

Row

s which consists of multiple

Column

s. The task would be to calculate the totals for every given column identified by its

name

:


fun calculateTotals(data: Grid) = data.rows
    .flatMap(Row::data)
    .groupingBy(Column<*>::name)
    .fold(0.0) { accumulator, (_, value) ->
        accumulator + when (value) {
            is Number -> value.toDouble()
            else -> 0.0
        }
    }

Using functions from the Kotlin standard library, we can do the following:
1. collect all columns from all rows in a single collection using

flatMap

2. group these columns by their name using

groupingBy

3. accumulate the grouped columns by summing up their values

The above is just a single straightforward example that nicely demonstrates what you can do with the given collection functions. As I said earlier, I make use of these functions every day, I use it extensively, and I don’t want to miss it anymore.

You need to write less code

One of the most significant advantages of the functional programming style is the fact that you have to write less code overall. You make use of so-called internal iterations rather than specifying how to iterate a given collection explicitly. Loops sound easy at the beginning, and everybody should be able to apply them correctly. Still, they can easily cause hard-to-find bugs, which is a common problem of boilerplate code. The idea of functional APIs is that you can focus on the what instead of the how and thus don’t iterate collections explicitly but rather use functions like

map

,

filter

etc. which handle the iteration for you.

Less Boilerplate – Fewer errors in general

Boilerplate code can be the source of errors; naturally, the more code you need to write, the more potential bugs can be created. Since Kotlin removes the necessity for a lot of tedious boilerplate codes, the language makes you introduce fewer logic errors in general. An excellent example of this is the singleton pattern. Implementing it correctly is not as simple as you might think. You have to handle simultaneous access to singletons, which makes it hard to implement the initialization code of such an object. There are different approaches to this issue, all of which can cause potential issues if written manually. Kotlin, through its

object

construct, abstracts this for the developer and does not require you to write the recurring code every time.

Easier to debug and maintain

While in Java you have to spend much time reading and understanding boilerplate code, this is not that much of an issue in Kotlin for the same reasons already mentioned: a sophisticated set of features and a more concise language in general. Moving an existing Java code base to Kotlin reduces the code size by ~40% if done correctly. This, of course, makes Kotlin code much easier to read, debug and also maintain. To be fair, a rich feature set can easily be abused and may lead to hard-to-read code if used without care. So don’t write the code for you but the people who have to maintain it in the future.

It’s fun

All the reasons mentioned above make Kotlin a language that is fun. A pragmatic, concise and intuitive language is the best tool a programmer can think of, and you should not be using anything else. Having fun automatically leads to more productivity as well.

What you should do before calling yourself a Kotlin developer

I want to note that I consider it extremely helpful to know your toolset accurately. I took much time to learn Kotlin, primarily how it works and what features it provides, which everyone should do before writing serious Kotlin code. As a Java developer, you can quickly write compiling Kotlin code, but that’s still different from writing idiomatic Kotlin code. It won’t be sufficient to google for StackOverflow posts all the time. You should incorporate some fundamental techniques before getting started. I recommend studying the complete Kotlin documentation, which you can do in only a few days. On top of that, the book Kotlin in Action is the best resource you can find, and I highly recommend it.

Conclusion

Putting away Java in favor of Kotlin improved my programming skills and made me much more productive in general. I feel more joy, introduce fewer errors and feel less bugged than I did with Java. I don’t want to say that only Kotlin can do this for you too. However, maybe it’s time to get started with a more contemporary language to broaden your horizon and become more productive on the side.

The post How Kotlin makes me a more productive software developer appeared first on Kotlin Expertise Blog.

Continue Reading How Kotlin makes me a more productive software developer

How Kotlin makes me a more productive software developer

How Kotlin makes me a more productive software developer

I’ve been writing JVM code for more than seven years now, and I did so mainly using Java. This changed about two years ago when I picked up Kotlin. By now, I managed to drop the Java language more-or-less entirely in favor of Kotlin. I did this because I feel much more productive with the language. It lets me focus more on the business logic rather than forcing me to write boilerplate code over and over again. In this post, I tell you how Kotlin makes me a more productive developer.
I certainly know Kotlin much better than I ever knew Java. FWIW, I had been certified as a Java expert by Oracle some years back. Still, Kotlin became my native programming language, and I want to encourage you to consider it too. When I talk about my Kotlin productivity, this probably is based on personal sentiment. I’m in a particular situation as I picked up the language rather early, right before 1.0 was released, and also worked as a teacher for the language ever since. Nevertheless, I’m convinced that some of the arguments in favor of Kotlin apply to many more of you, so let’s see what I’m talking about.

My JVM background

I used Java intensively for some years and wrote much productive code with the language. Java was my first language, and I did not know other languages too well at that point. Despite not having seen many other languages, I never really felt much joy when using Java, which changed when Java 8 arrived back in 2014. I immediately fell in love with the functional aspects that were added to the language and used lambdas and streams all over our code base. There might have been some situations in which I shouldn’t have done so, but it was bleeding Java edge, and I loved it. At that time, I started looking into other JVM languages and started to learn Scala at some point. I began by reading its documentation which was fun at first but then quickly started to become scary. I never really gave it a proper chance but looking back, I don’t regret putting it away after only a few weeks.

Kotlin

I don’t quite remember where I heard about Kotlin for the first time. The only thing I do remember is that JetBrains was mentioned along with it. I’ve always been a fan of their products, and so it was clear that I had to investigate the language they created. Other than Scala, Kotlin has a very digestible documentation, and it never got scary when I read it. I remember that I binge-read it in only a few days and there were like two topics I didn’t quite understand directly and bookmarked for later. One of those topics was backing fields, and the other one was probably related to delegation support.
Another thing that made it super easy to pick up Kotlin was the excellent support in IntelliJ. I learned the language with the IDE and the documentation. Another resource I totally recommend is the book Kotlin in Action which also helped me a lot with understanding the inner workings of the language better.

Standard Library

Kotlin has a fantastic standard library. If you think that Java also does, I can assure you that it is much weaker than Kotlin’s. You won’t need external libraries for everyday tasks like checking whether a

String

is blank or copying streams around. Kotlin provides all that and much more. It comes with an extremely sophisticated collections API, defines commonly needed extension functions on default types and finally gives the developer the option to add their own functions via extensions. You can find an excellent article on a bunch of standard functions here for example.

Feature-rich language

This one should be obvious. Especially when you’re coming from a language like Java, you will be blessed by the crisp features Kotlin provides. Think about null-safety, extension functions, easier generics or its catchy concurrency means provided by coroutines for instance – they all make us more productive and make the language more enjoyable.

Kotlin is intuitive

As a result of the fantastic standard library and the rich feature set, Kotlin is a very intuitive language. Frequently, you may try to perform some action on a given type and see what existing functions the IDE suggests. It then often happens that you find the function you were looking for already defined. Examples of this would be String::substringBefore, File::extension or Iterable::toSet.

Functional Style

When we talk about the standard library and also how intuitive the language is by itself, we also want to mention the functional aspects of the language. In this part, I particularly want to focus on functions. As you might already know, functions are first class citizens in Kotlin. You can declare variables holding them, pass them around and even return functions from other functions. You find lambdas (undeclared and directly passed functions) in every Kotlin code base. They are heavily used in the Kotlin standard library too. One example of this is the very helpful set of scope functions, which you can learn about here. Of course, lambdas are a vital ingredient to the collections API, i.e., stuff defined in

kotlin.collections

, as well. I can’t even tell how many times I use these functions in my day to day work. It somewhat gives me the creeps when I think about transforming collections within traditional

for

loops and how difficult it was to perform similar tasks in Java, especially before Java 8. Let’s see an example in action. Let’s assume we have some table/grid data modeled as follows:

Example


data class Grid(val rows: List<Row>)
data class Row(val data: List<Column<*>>)
data class Column<T>(val name: String, val value: T)

A

Grid

has multiple

Row

s which consists of multiple

Column

s. The task would be to calculate the totals for every given column identified by its

name

:


fun calculateTotals(data: Grid) = data.rows
    .flatMap(Row::data)
    .groupingBy(Column<*>::name)
    .fold(0.0) { accumulator, (_, value) ->
        accumulator + when (value) {
            is Number -> value.toDouble()
            else -> 0.0
        }
    }

Using functions from the Kotlin standard library, we can do the following:
1. collect all columns from all rows in a single collection using

flatMap

2. group these columns by their name using

groupingBy

3. accumulate the grouped columns by summing up their values

The above is just a single straightforward example that nicely demonstrates what you can do with the given collection functions. As I said earlier, I make use of these functions every day, I use it extensively, and I don’t want to miss it anymore.

You need to write less code

One of the most significant advantages of the functional programming style is the fact that you have to write less code overall. You make use of so-called internal iterations rather than specifying how to iterate a given collection explicitly. Loops sound easy at the beginning, and everybody should be able to apply them correctly. Still, they can easily cause hard-to-find bugs, which is a common problem of boilerplate code. The idea of functional APIs is that you can focus on the what instead of the how and thus don’t iterate collections explicitly but rather use functions like

map

,

filter

etc. which handle the iteration for you.

Less Boilerplate – Fewer errors in general

Boilerplate code can be the source of errors; naturally, the more code you need to write, the more potential bugs can be created. Since Kotlin removes the necessity for a lot of tedious boilerplate codes, the language makes you introduce fewer logic errors in general. An excellent example of this is the singleton pattern. Implementing it correctly is not as simple as you might think. You have to handle simultaneous access to singletons, which makes it hard to implement the initialization code of such an object. There are different approaches to this issue, all of which can cause potential issues if written manually. Kotlin, through its

object

construct, abstracts this for the developer and does not require you to write the recurring code every time.

Easier to debug and maintain

While in Java you have to spend much time reading and understanding boilerplate code, this is not that much of an issue in Kotlin for the same reasons already mentioned: a sophisticated set of features and a more concise language in general. Moving an existing Java code base to Kotlin reduces the code size by ~40% if done correctly. This, of course, makes Kotlin code much easier to read, debug and also maintain. To be fair, a rich feature set can easily be abused and may lead to hard-to-read code if used without care. So don’t write the code for you but the people who have to maintain it in the future.

It’s fun

All the reasons mentioned above make Kotlin a language that is fun. A pragmatic, concise and intuitive language is the best tool a programmer can think of, and you should not be using anything else. Having fun automatically leads to more productivity as well.

What you should do before calling yourself a Kotlin developer

I want to note that I consider it extremely helpful to know your toolset accurately. I took much time to learn Kotlin, primarily how it works and what features it provides, which everyone should do before writing serious Kotlin code. As a Java developer, you can quickly write compiling Kotlin code, but that’s still different from writing idiomatic Kotlin code. It won’t be sufficient to google for StackOverflow posts all the time. You should incorporate some fundamental techniques before getting started. I recommend studying the complete Kotlin documentation, which you can do in only a few days. On top of that, the book Kotlin in Action is the best resource you can find, and I highly recommend it.

Conclusion

Putting away Java in favor of Kotlin improved my programming skills and made me much more productive in general. I feel more joy, introduce fewer errors and feel less bugged than I did with Java. I don’t want to say that only Kotlin can do this for you too. However, maybe it’s time to get started with a more contemporary language to broaden your horizon and become more productive on the side.

The post How Kotlin makes me a more productive software developer appeared first on Kotlin Expertise Blog.

Continue Reading How Kotlin makes me a more productive software developer

How Kotlin makes me a more productive software developer

How Kotlin makes me a more productive software developer

I’ve been writing JVM code for more than seven years now, and I did so mainly using Java. This changed about two years ago when I picked up Kotlin. By now, I managed to drop the Java language more-or-less entirely in favor of Kotlin. I did this because I feel much more productive with the language. It lets me focus more on the business logic rather than forcing me to write boilerplate code over and over again. In this post, I tell you how Kotlin makes me a more productive developer.
I certainly know Kotlin much better than I ever knew Java. FWIW, I had been certified as a Java expert by Oracle some years back. Still, Kotlin became my native programming language, and I want to encourage you to consider it too. When I talk about my Kotlin productivity, this probably is based on personal sentiment. I’m in a particular situation as I picked up the language rather early, right before 1.0 was released, and also worked as a teacher for the language ever since. Nevertheless, I’m convinced that some of the arguments in favor of Kotlin apply to many more of you, so let’s see what I’m talking about.

My JVM background

I used Java intensively for some years and wrote much productive code with the language. Java was my first language, and I did not know other languages too well at that point. Despite not having seen many other languages, I never really felt much joy when using Java, which changed when Java 8 arrived back in 2014. I immediately fell in love with the functional aspects that were added to the language and used lambdas and streams all over our code base. There might have been some situations in which I shouldn’t have done so, but it was bleeding Java edge, and I loved it. At that time, I started looking into other JVM languages and started to learn Scala at some point. I began by reading its documentation which was fun at first but then quickly started to become scary. I never really gave it a proper chance but looking back, I don’t regret putting it away after only a few weeks.

Kotlin

I don’t quite remember where I heard about Kotlin for the first time. The only thing I do remember is that JetBrains was mentioned along with it. I’ve always been a fan of their products, and so it was clear that I had to investigate the language they created. Other than Scala, Kotlin has a very digestible documentation, and it never got scary when I read it. I remember that I binge-read it in only a few days and there were like two topics I didn’t quite understand directly and bookmarked for later. One of those topics was backing fields, and the other one was probably related to delegation support.
Another thing that made it super easy to pick up Kotlin was the excellent support in IntelliJ. I learned the language with the IDE and the documentation. Another resource I totally recommend is the book Kotlin in Action which also helped me a lot with understanding the inner workings of the language better.

Standard Library

Kotlin has a fantastic standard library. If you think that Java also does, I can assure you that it is much weaker than Kotlin’s. You won’t need external libraries for everyday tasks like checking whether a

String

is blank or copying streams around. Kotlin provides all that and much more. It comes with an extremely sophisticated collections API, defines commonly needed extension functions on default types and finally gives the developer the option to add their own functions via extensions. You can find an excellent article on a bunch of standard functions here for example.

Feature-rich language

This one should be obvious. Especially when you’re coming from a language like Java, you will be blessed by the crisp features Kotlin provides. Think about null-safety, extension functions, easier generics or its catchy concurrency means provided by coroutines for instance – they all make us more productive and make the language more enjoyable.

Kotlin is intuitive

As a result of the fantastic standard library and the rich feature set, Kotlin is a very intuitive language. Frequently, you may try to perform some action on a given type and see what existing functions the IDE suggests. It then often happens that you find the function you were looking for already defined. Examples of this would be String::substringBefore, File::extension or Iterable::toSet.

Functional Style

When we talk about the standard library and also how intuitive the language is by itself, we also want to mention the functional aspects of the language. In this part, I particularly want to focus on functions. As you might already know, functions are first class citizens in Kotlin. You can declare variables holding them, pass them around and even return functions from other functions. You find lambdas (undeclared and directly passed functions) in every Kotlin code base. They are heavily used in the Kotlin standard library too. One example of this is the very helpful set of scope functions, which you can learn about here. Of course, lambdas are a vital ingredient to the collections API, i.e., stuff defined in

kotlin.collections

, as well. I can’t even tell how many times I use these functions in my day to day work. It somewhat gives me the creeps when I think about transforming collections within traditional

for

loops and how difficult it was to perform similar tasks in Java, especially before Java 8. Let’s see an example in action. Let’s assume we have some table/grid data modeled as follows:

Example


data class Grid(val rows: List<Row>)
data class Row(val data: List<Column<*>>)
data class Column<T>(val name: String, val value: T)

A

Grid

has multiple

Row

s which consists of multiple

Column

s. The task would be to calculate the totals for every given column identified by its

name

:


fun calculateTotals(data: Grid) = data.rows
    .flatMap(Row::data)
    .groupingBy(Column<*>::name)
    .fold(0.0) { accumulator, (_, value) ->
        accumulator + when (value) {
            is Number -> value.toDouble()
            else -> 0.0
        }
    }

Using functions from the Kotlin standard library, we can do the following:
1. collect all columns from all rows in a single collection using

flatMap

2. group these columns by their name using

groupingBy

3. accumulate the grouped columns by summing up their values

The above is just a single straightforward example that nicely demonstrates what you can do with the given collection functions. As I said earlier, I make use of these functions every day, I use it extensively, and I don’t want to miss it anymore.

You need to write less code

One of the most significant advantages of the functional programming style is the fact that you have to write less code overall. You make use of so-called internal iterations rather than specifying how to iterate a given collection explicitly. Loops sound easy at the beginning, and everybody should be able to apply them correctly. Still, they can easily cause hard-to-find bugs, which is a common problem of boilerplate code. The idea of functional APIs is that you can focus on the what instead of the how and thus don’t iterate collections explicitly but rather use functions like

map

,

filter

etc. which handle the iteration for you.

Less Boilerplate – Fewer errors in general

Boilerplate code can be the source of errors; naturally, the more code you need to write, the more potential bugs can be created. Since Kotlin removes the necessity for a lot of tedious boilerplate codes, the language makes you introduce fewer logic errors in general. An excellent example of this is the singleton pattern. Implementing it correctly is not as simple as you might think. You have to handle simultaneous access to singletons, which makes it hard to implement the initialization code of such an object. There are different approaches to this issue, all of which can cause potential issues if written manually. Kotlin, through its

object

construct, abstracts this for the developer and does not require you to write the recurring code every time.

Easier to debug and maintain

While in Java you have to spend much time reading and understanding boilerplate code, this is not that much of an issue in Kotlin for the same reasons already mentioned: a sophisticated set of features and a more concise language in general. Moving an existing Java code base to Kotlin reduces the code size by ~40% if done correctly. This, of course, makes Kotlin code much easier to read, debug and also maintain. To be fair, a rich feature set can easily be abused and may lead to hard-to-read code if used without care. So don’t write the code for you but the people who have to maintain it in the future.

It’s fun

All the reasons mentioned above make Kotlin a language that is fun. A pragmatic, concise and intuitive language is the best tool a programmer can think of, and you should not be using anything else. Having fun automatically leads to more productivity as well.

What you should do before calling yourself a Kotlin developer

I want to note that I consider it extremely helpful to know your toolset accurately. I took much time to learn Kotlin, primarily how it works and what features it provides, which everyone should do before writing serious Kotlin code. As a Java developer, you can quickly write compiling Kotlin code, but that’s still different from writing idiomatic Kotlin code. It won’t be sufficient to google for StackOverflow posts all the time. You should incorporate some fundamental techniques before getting started. I recommend studying the complete Kotlin documentation, which you can do in only a few days. On top of that, the book Kotlin in Action is the best resource you can find, and I highly recommend it.

Conclusion

Putting away Java in favor of Kotlin improved my programming skills and made me much more productive in general. I feel more joy, introduce fewer errors and feel less bugged than I did with Java. I don’t want to say that only Kotlin can do this for you too. However, maybe it’s time to get started with a more contemporary language to broaden your horizon and become more productive on the side.

The post How Kotlin makes me a more productive software developer appeared first on Kotlin Expertise Blog.

Continue Reading How Kotlin makes me a more productive software developer

How Kotlin makes me a more productive software developer

How Kotlin makes me a more productive software developer

I’ve been writing JVM code for more than seven years now, and I did so mainly using Java. This changed about two years ago when I picked up Kotlin. By now, I managed to drop the Java language more-or-less entirely in favor of Kotlin. I did this because I feel much more productive with the language. It lets me focus more on the business logic rather than forcing me to write boilerplate code over and over again. In this post, I tell you how Kotlin makes me a more productive developer.
I certainly know Kotlin much better than I ever knew Java. FWIW, I had been certified as a Java expert by Oracle some years back. Still, Kotlin became my native programming language, and I want to encourage you to consider it too. When I talk about my Kotlin productivity, this probably is based on personal sentiment. I’m in a particular situation as I picked up the language rather early, right before 1.0 was released, and also worked as a teacher for the language ever since. Nevertheless, I’m convinced that some of the arguments in favor of Kotlin apply to many more of you, so let’s see what I’m talking about.

My JVM background

I used Java intensively for some years and wrote much productive code with the language. Java was my first language, and I did not know other languages too well at that point. Despite not having seen many other languages, I never really felt much joy when using Java, which changed when Java 8 arrived back in 2014. I immediately fell in love with the functional aspects that were added to the language and used lambdas and streams all over our code base. There might have been some situations in which I shouldn’t have done so, but it was bleeding Java edge, and I loved it. At that time, I started looking into other JVM languages and started to learn Scala at some point. I began by reading its documentation which was fun at first but then quickly started to become scary. I never really gave it a proper chance but looking back, I don’t regret putting it away after only a few weeks.

Kotlin

I don’t quite remember where I heard about Kotlin for the first time. The only thing I do remember is that JetBrains was mentioned along with it. I’ve always been a fan of their products, and so it was clear that I had to investigate the language they created. Other than Scala, Kotlin has a very digestible documentation, and it never got scary when I read it. I remember that I binge-read it in only a few days and there were like two topics I didn’t quite understand directly and bookmarked for later. One of those topics was backing fields, and the other one was probably related to delegation support.
Another thing that made it super easy to pick up Kotlin was the excellent support in IntelliJ. I learned the language with the IDE and the documentation. Another resource I totally recommend is the book Kotlin in Action which also helped me a lot with understanding the inner workings of the language better.

Standard Library

Kotlin has a fantastic standard library. If you think that Java also does, I can assure you that it is much weaker than Kotlin’s. You won’t need external libraries for everyday tasks like checking whether a

String

is blank or copying streams around. Kotlin provides all that and much more. It comes with an extremely sophisticated collections API, defines commonly needed extension functions on default types and finally gives the developer the option to add their own functions via extensions. You can find an excellent article on a bunch of standard functions here for example.

Feature-rich language

This one should be obvious. Especially when you’re coming from a language like Java, you will be blessed by the crisp features Kotlin provides. Think about null-safety, extension functions, easier generics or its catchy concurrency means provided by coroutines for instance – they all make us more productive and make the language more enjoyable.

Kotlin is intuitive

As a result of the fantastic standard library and the rich feature set, Kotlin is a very intuitive language. Frequently, you may try to perform some action on a given type and see what existing functions the IDE suggests. It then often happens that you find the function you were looking for already defined. Examples of this would be String::substringBefore, File::extension or Iterable::toSet.

Functional Style

When we talk about the standard library and also how intuitive the language is by itself, we also want to mention the functional aspects of the language. In this part, I particularly want to focus on functions. As you might already know, functions are first class citizens in Kotlin. You can declare variables holding them, pass them around and even return functions from other functions. You find lambdas (undeclared and directly passed functions) in every Kotlin code base. They are heavily used in the Kotlin standard library too. One example of this is the very helpful set of scope functions, which you can learn about here. Of course, lambdas are a vital ingredient to the collections API, i.e., stuff defined in

kotlin.collections

, as well. I can’t even tell how many times I use these functions in my day to day work. It somewhat gives me the creeps when I think about transforming collections within traditional

for

loops and how difficult it was to perform similar tasks in Java, especially before Java 8. Let’s see an example in action. Let’s assume we have some table/grid data modeled as follows:

Example


data class Grid(val rows: List<Row>)
data class Row(val data: List<Column<*>>)
data class Column<T>(val name: String, val value: T)

A

Grid

has multiple

Row

s which consists of multiple

Column

s. The task would be to calculate the totals for every given column identified by its

name

:


fun calculateTotals(data: Grid) = data.rows
    .flatMap(Row::data)
    .groupingBy(Column<*>::name)
    .fold(0.0) { accumulator, (_, value) ->
        accumulator + when (value) {
            is Number -> value.toDouble()
            else -> 0.0
        }
    }

Using functions from the Kotlin standard library, we can do the following:
1. collect all columns from all rows in a single collection using

flatMap

2. group these columns by their name using

groupingBy

3. accumulate the grouped columns by summing up their values

The above is just a single straightforward example that nicely demonstrates what you can do with the given collection functions. As I said earlier, I make use of these functions every day, I use it extensively, and I don’t want to miss it anymore.

You need to write less code

One of the most significant advantages of the functional programming style is the fact that you have to write less code overall. You make use of so-called internal iterations rather than specifying how to iterate a given collection explicitly. Loops sound easy at the beginning, and everybody should be able to apply them correctly. Still, they can easily cause hard-to-find bugs, which is a common problem of boilerplate code. The idea of functional APIs is that you can focus on the what instead of the how and thus don’t iterate collections explicitly but rather use functions like

map

,

filter

etc. which handle the iteration for you.

Less Boilerplate – Fewer errors in general

Boilerplate code can be the source of errors; naturally, the more code you need to write, the more potential bugs can be created. Since Kotlin removes the necessity for a lot of tedious boilerplate codes, the language makes you introduce fewer logic errors in general. An excellent example of this is the singleton pattern. Implementing it correctly is not as simple as you might think. You have to handle simultaneous access to singletons, which makes it hard to implement the initialization code of such an object. There are different approaches to this issue, all of which can cause potential issues if written manually. Kotlin, through its

object

construct, abstracts this for the developer and does not require you to write the recurring code every time.

Easier to debug and maintain

While in Java you have to spend much time reading and understanding boilerplate code, this is not that much of an issue in Kotlin for the same reasons already mentioned: a sophisticated set of features and a more concise language in general. Moving an existing Java code base to Kotlin reduces the code size by ~40% if done correctly. This, of course, makes Kotlin code much easier to read, debug and also maintain. To be fair, a rich feature set can easily be abused and may lead to hard-to-read code if used without care. So don’t write the code for you but the people who have to maintain it in the future.

It’s fun

All the reasons mentioned above make Kotlin a language that is fun. A pragmatic, concise and intuitive language is the best tool a programmer can think of, and you should not be using anything else. Having fun automatically leads to more productivity as well.

What you should do before calling yourself a Kotlin developer

I want to note that I consider it extremely helpful to know your toolset accurately. I took much time to learn Kotlin, primarily how it works and what features it provides, which everyone should do before writing serious Kotlin code. As a Java developer, you can quickly write compiling Kotlin code, but that’s still different from writing idiomatic Kotlin code. It won’t be sufficient to google for StackOverflow posts all the time. You should incorporate some fundamental techniques before getting started. I recommend studying the complete Kotlin documentation, which you can do in only a few days. On top of that, the book Kotlin in Action is the best resource you can find, and I highly recommend it.

Conclusion

Putting away Java in favor of Kotlin improved my programming skills and made me much more productive in general. I feel more joy, introduce fewer errors and feel less bugged than I did with Java. I don’t want to say that only Kotlin can do this for you too. However, maybe it’s time to get started with a more contemporary language to broaden your horizon and become more productive on the side.

The post How Kotlin makes me a more productive software developer appeared first on Kotlin Expertise Blog.

Continue Reading How Kotlin makes me a more productive software developer

How Kotlin makes me a more productive software developer

How Kotlin makes me a more productive software developer

I’ve been writing JVM code for more than seven years now, and I did so mainly using Java. This changed about two years ago when I picked up Kotlin. By now, I managed to drop the Java language more-or-less entirely in favor of Kotlin. I did this because I feel much more productive with the language. It lets me focus more on the business logic rather than forcing me to write boilerplate code over and over again. In this post, I tell you how Kotlin makes me a more productive developer.
I certainly know Kotlin much better than I ever knew Java. FWIW, I had been certified as a Java expert by Oracle some years back. Still, Kotlin became my native programming language, and I want to encourage you to consider it too. When I talk about my Kotlin productivity, this probably is based on personal sentiment. I’m in a particular situation as I picked up the language rather early, right before 1.0 was released, and also worked as a teacher for the language ever since. Nevertheless, I’m convinced that some of the arguments in favor of Kotlin apply to many more of you, so let’s see what I’m talking about.

My JVM background

I used Java intensively for some years and wrote much productive code with the language. Java was my first language, and I did not know other languages too well at that point. Despite not having seen many other languages, I never really felt much joy when using Java, which changed when Java 8 arrived back in 2014. I immediately fell in love with the functional aspects that were added to the language and used lambdas and streams all over our code base. There might have been some situations in which I shouldn’t have done so, but it was bleeding Java edge, and I loved it. At that time, I started looking into other JVM languages and started to learn Scala at some point. I began by reading its documentation which was fun at first but then quickly started to become scary. I never really gave it a proper chance but looking back, I don’t regret putting it away after only a few weeks.

Kotlin

I don’t quite remember where I heard about Kotlin for the first time. The only thing I do remember is that JetBrains was mentioned along with it. I’ve always been a fan of their products, and so it was clear that I had to investigate the language they created. Other than Scala, Kotlin has a very digestible documentation, and it never got scary when I read it. I remember that I binge-read it in only a few days and there were like two topics I didn’t quite understand directly and bookmarked for later. One of those topics was backing fields, and the other one was probably related to delegation support.
Another thing that made it super easy to pick up Kotlin was the excellent support in IntelliJ. I learned the language with the IDE and the documentation. Another resource I totally recommend is the book Kotlin in Action which also helped me a lot with understanding the inner workings of the language better.

Standard Library

Kotlin has a fantastic standard library. If you think that Java also does, I can assure you that it is much weaker than Kotlin’s. You won’t need external libraries for everyday tasks like checking whether a

String

is blank or copying streams around. Kotlin provides all that and much more. It comes with an extremely sophisticated collections API, defines commonly needed extension functions on default types and finally gives the developer the option to add their own functions via extensions. You can find an excellent article on a bunch of standard functions here for example.

Feature-rich language

This one should be obvious. Especially when you’re coming from a language like Java, you will be blessed by the crisp features Kotlin provides. Think about null-safety, extension functions, easier generics or its catchy concurrency means provided by coroutines for instance – they all make us more productive and make the language more enjoyable.

Kotlin is intuitive

As a result of the fantastic standard library and the rich feature set, Kotlin is a very intuitive language. Frequently, you may try to perform some action on a given type and see what existing functions the IDE suggests. It then often happens that you find the function you were looking for already defined. Examples of this would be String::substringBefore, File::extension or Iterable::toSet.

Functional Style

When we talk about the standard library and also how intuitive the language is by itself, we also want to mention the functional aspects of the language. In this part, I particularly want to focus on functions. As you might already know, functions are first class citizens in Kotlin. You can declare variables holding them, pass them around and even return functions from other functions. You find lambdas (undeclared and directly passed functions) in every Kotlin code base. They are heavily used in the Kotlin standard library too. One example of this is the very helpful set of scope functions, which you can learn about here. Of course, lambdas are a vital ingredient to the collections API, i.e., stuff defined in

kotlin.collections

, as well. I can’t even tell how many times I use these functions in my day to day work. It somewhat gives me the creeps when I think about transforming collections within traditional

for

loops and how difficult it was to perform similar tasks in Java, especially before Java 8. Let’s see an example in action. Let’s assume we have some table/grid data modeled as follows:

Example


data class Grid(val rows: List<Row>)
data class Row(val data: List<Column<*>>)
data class Column<T>(val name: String, val value: T)

A

Grid

has multiple

Row

s which consists of multiple

Column

s. The task would be to calculate the totals for every given column identified by its

name

:


fun calculateTotals(data: Grid) = data.rows
    .flatMap(Row::data)
    .groupingBy(Column<*>::name)
    .fold(0.0) { accumulator, (_, value) ->
        accumulator + when (value) {
            is Number -> value.toDouble()
            else -> 0.0
        }
    }

Using functions from the Kotlin standard library, we can do the following:
1. collect all columns from all rows in a single collection using

flatMap

2. group these columns by their name using

groupingBy

3. accumulate the grouped columns by summing up their values

The above is just a single straightforward example that nicely demonstrates what you can do with the given collection functions. As I said earlier, I make use of these functions every day, I use it extensively, and I don’t want to miss it anymore.

You need to write less code

One of the most significant advantages of the functional programming style is the fact that you have to write less code overall. You make use of so-called internal iterations rather than specifying how to iterate a given collection explicitly. Loops sound easy at the beginning, and everybody should be able to apply them correctly. Still, they can easily cause hard-to-find bugs, which is a common problem of boilerplate code. The idea of functional APIs is that you can focus on the what instead of the how and thus don’t iterate collections explicitly but rather use functions like

map

,

filter

etc. which handle the iteration for you.

Less Boilerplate – Fewer errors in general

Boilerplate code can be the source of errors; naturally, the more code you need to write, the more potential bugs can be created. Since Kotlin removes the necessity for a lot of tedious boilerplate codes, the language makes you introduce fewer logic errors in general. An excellent example of this is the singleton pattern. Implementing it correctly is not as simple as you might think. You have to handle simultaneous access to singletons, which makes it hard to implement the initialization code of such an object. There are different approaches to this issue, all of which can cause potential issues if written manually. Kotlin, through its

object

construct, abstracts this for the developer and does not require you to write the recurring code every time.

Easier to debug and maintain

While in Java you have to spend much time reading and understanding boilerplate code, this is not that much of an issue in Kotlin for the same reasons already mentioned: a sophisticated set of features and a more concise language in general. Moving an existing Java code base to Kotlin reduces the code size by ~40% if done correctly. This, of course, makes Kotlin code much easier to read, debug and also maintain. To be fair, a rich feature set can easily be abused and may lead to hard-to-read code if used without care. So don’t write the code for you but the people who have to maintain it in the future.

It’s fun

All the reasons mentioned above make Kotlin a language that is fun. A pragmatic, concise and intuitive language is the best tool a programmer can think of, and you should not be using anything else. Having fun automatically leads to more productivity as well.

What you should do before calling yourself a Kotlin developer

I want to note that I consider it extremely helpful to know your toolset accurately. I took much time to learn Kotlin, primarily how it works and what features it provides, which everyone should do before writing serious Kotlin code. As a Java developer, you can quickly write compiling Kotlin code, but that’s still different from writing idiomatic Kotlin code. It won’t be sufficient to google for StackOverflow posts all the time. You should incorporate some fundamental techniques before getting started. I recommend studying the complete Kotlin documentation, which you can do in only a few days. On top of that, the book Kotlin in Action is the best resource you can find, and I highly recommend it.

Conclusion

Putting away Java in favor of Kotlin improved my programming skills and made me much more productive in general. I feel more joy, introduce fewer errors and feel less bugged than I did with Java. I don’t want to say that only Kotlin can do this for you too. However, maybe it’s time to get started with a more contemporary language to broaden your horizon and become more productive on the side.

The post How Kotlin makes me a more productive software developer appeared first on Kotlin Expertise Blog.

Continue Reading How Kotlin makes me a more productive software developer

End of content

No more pages to load