42

New in Kotlin 1.3: inline classes

 5 years ago
source link: https://www.tuicool.com/articles/hit/6jMjYfn
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Programming languages, when it comes to types, can be dynamic or static. Then, both categories can be weakly or strongly typed. It turns out, even statically and strongly typed languages are not all the same.

Let's consider an example domain model, a Contact . It holds a name , and an email . Both properties are text data, and, in languages like Java or Kotlin, can be modeled using String type:

data class Contact(val name: String, val email: String)

The code above is "stringly-typed". Why? This is both valid and meaningful:

val friend = Contact(name = "John Doe", email = "[email protected]")

On the other hand, this is valid but meaningless:

val friend = Contact(name = "[email protected]", email = "John Doe")

Languages like Ada promote a different approach. All values, even when the underlying representation is the same, should have a different type:

type Name_Type is new Unbounded_String;
type Email_Type is new Unbounded_String;

type Contact is
   record
      Name  : Name_Type;
      Email : Email_Type;
   end record;

Then this code is valid, meaningful and is type-checked at compile-time:

Friends_Name  : Name_Type  := To_Unbounded_String ("John Doe");
Friends_Email : Email_Type := To_Unbounded_String ("[email protected]");

Friend        : Contact    := Contact'(Name => Friends_Name, Email => Friends_Email);

And this will fail at compile-time:

Friends_Name  : Name_Type  := To_Unbounded_String ("John Doe");
Friends_Email : Email_Type := To_Unbounded_String ("[email protected]");

Friend        : Contact    := Contact'(Name => Friends_Email, Email => Friends_Name);

Of course, this solution can be applied to our Kotlin code but at a cost:

data class Name(val value: String)
data class Email(val value: String)

data class Contact(val name: Name, val email: Email)

Now the Contact API is typesafe. One can't provide Name("[email protected]") as an email , or vice versa. Unfortunately data classes wrap the underlying value in a runtime object. It results in a performance hit due to heap allocations, and the fact the JVM treats primitive types with special care and optimizes them heavily.

Thankfully, Kotlin 1.3 introduces inline classes. They are declared using inline keyword, placed before the class keyword. An inline class must have a single property initialized in the primary constructor. At runtime, the wrapper type is erased, and the value is represented just as a raw property.

inline class Name(val value: String)
inline class Email(val value: String)

data class Contact(val name: Name, val email: Email)

It is important to note the inline classes feature is still marked as experimental, and subject to change. It can be enabled in Gradle by passing the proper argument to the Kotlin compiler:

compileKotlin {
    kotlinOptions.freeCompilerArgs += ["-XXLanguage:+InlineClasses"]
}

You can find more on the topic at the official Kotlin documentation page .


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK