Hi, everyone! Iâm Svetlana Isakova,Â
a Developer Advocate at JetBrains. In this video, I wanna talk about one of theÂ
new language features of the Kotlin 1.5 release:Â Â inline value classes. In simple words, an inline class can wrapÂ
a value without any additional overhead. This feature has been available for some time,  it was added in an experimentalÂ
state in Kotlin 1.2.30. And Kotlin 1.5 stabilizes thisÂ
functionality with some changes. Letâs start with an example. I wanna use Duration API as an example, toÂ
define a problem and discuss different solutions. Duration represents the amount ofÂ
time between two time instants. Without inline classes,  Duration can be implemented either viaÂ
primitives, or using a regular class. Letâs try primitives first. We need a functionÂ
that does something after a given timeout. How to pass a timeout parameter?Â
We can use primitives, like âlongâ. However, it might be reallyÂ
confusing on the call site:Â Â we pass an integer constant but we donâtÂ
know immediately whether itâs seconds,  or milliseconds or i-donât-knowÂ
minutes. Itâs not a type-safe solution. We could sort of overload this function by addingÂ
the time units to its name but itâs too verbose. Defining a separate Duration classÂ
solves the type safety problem.  We can define auxiliary functionsÂ
like seconds or minutes to emphasize  the time units. Itâs no longer error-proneÂ
to use the new greetAfterTimeout function. We have explicit units in the code, cool. The only problem of this approach is that an extraÂ
object is allocated to store the timeout duration.  After gaining type safety we lost performance. Inline value classes solve that. TheyÂ
combine performance of primitive types  and type safety of regular classes. Starting from 1.5 you define an inline classÂ
differently: as a value class annotated with  the @JvmInline annotation.
But the concept is the same. Under the hood, the compiler replacesÂ
the `Duration` parameter with `Long`. That means no extra object isÂ
allocated when you pass a value! In this example, the compilerÂ
replaces the Duration argument value with the underlying long constant in the bytecode. In the next example, we use the nice âsecondsâÂ
function which returns the Duration value,  and the compiler also replaces it withÂ
the corresponding constant under the hood. Thatâs what I mean by saying that
inline value classes combine the  performance of primitive types andÂ
type safety of regular classes. No extra objects are allocated,Â
itâs primitives under the hood. And explicit units in the codeÂ
demonstrate the type safety:Â Â duration is represented by aÂ
separate type, itâs not any number. The Kotlin standard library already definesÂ
several useful inline value classes. First of all, note that the standard libraryÂ
contains the experimental Duration class  which should be used to express durationsÂ
for timeouts and for other needs. You canât call the constructor directly, youÂ
create Duration instances using auxiliary  functions defined in Duration companion object,Â
like Duration.seconds or Duration.minutes. This class was available in an experimental stateÂ
since 1.3.50 and it stays experimental so far because it was recently significantly changedÂ
both in the API and internal representation. Before, it stored the underlying valueÂ
as âDoubleâ property, not âLongâ. We used it as an example in theÂ
presentation â in real-life tasks,  you donât need to redefine it. TheÂ
library class Duration does the job. Other useful types implemented via inline valueÂ
classes mechanism are unsigned number types. For each primitive integer type, thereâs aÂ
corresponding unsigned type, like UInt, or ULong. They store non-negative values occupying theÂ
same memory as their regular counterparts. Under the hood, each of them isÂ
defined as an inline value class  wrapper over the corresponding integer type. Like in this case, UInt isÂ
a wrapper over an Int value. You can convert a regular integer valueÂ
to unsigned value by calling a function  like toUByte() or toUInt(). Alternatively,Â
you can define a constant with the âuâ tag. Arithmetic operations andÂ
comparisons are supported for them. Unsigned types were available for aÂ
long type in an experimental state,  and now they become stable. But note thatÂ
array of unsigned types remains in Beta. Of course, you can defineÂ
your own inline value classes. You mark the class as a value class andÂ
annotate it with the JvmInline annotation. An inline class can be a wrapper either for aÂ
primitive or for any reference type like String. Inline class is a wrapper for only oneÂ
property, and this property should be read-only. Mutable vars arenât allowed. As for regular classes,Â
inside inline value classes,  you can define member functions and properties. Since inline value class is a wrapper overÂ
one property, other properties are allowed  only if they donât have backing fields.
They should compute the value on each access,  like in this example. Mutable propertiesÂ
without backing fields are also allowed. Donât confuse inline valueÂ
classes with inline functions.  Member functions of an inline value classÂ
donât get inlined; they are different concepts. You can also define an init blockÂ
to provide the constructor logic. Inline value classes are supportedÂ
by the kotlinx.serialization library. You can mark an inlineÂ
value class as Serializable, and when encoding data to JSON format,  you see only the underlying valueÂ
included, not the whole class. If a regular class is encoded, you see it in theÂ
output as an extra class. Like in this example,  you see that the color is representedÂ
by a class having an RGB property. For inline classes, the value is encodedÂ
directly. And decoded correspondingly. Here, we now defined ColorÂ
as an inline value class. And you can notice that the integer RGBÂ
value is serialized directly, as âcolorâ. Letâs now glance at what happens under the hood. If you expect that an inline value class isÂ
always replaced with the underlying value,  thatâs not correct.
The wrapper is not always eliminated  in the bytecode, it happens only when possible. ItÂ
works very similarly to built-in primitive types. When you define a variable orÂ
pass it directly to a function,  its type gets replaced with the underlying value.
Here, during the compilation time, itâs `Duration`Â but itâs replaced with aÂ
primitive type in the bytecode. If you store a âdurationâ valueÂ
in a collection or pass it  to a generic function, however, it gets boxed.
Boxing and unboxing are made automatically by the  compiler, so you donât need to think about it,
but itâs useful to understand how it works. If a function takes an inline classÂ
as a parameter, its name is mangled. That means the compiler addsÂ
a suffix to its initial name,  like for âgreetAfterTimeoutâ in this example. That happens for two reasons:
first, that allows overloading a function  to take two different inline valueÂ
classes that wrap the same value. Like in this example. We haveÂ
two different ârecordâ functions  taking âNameâ and âPasswordâ as parameters. Without mangling, they would have theÂ
same JVM signature in the bytecode  and such code wonât compile. The second reason for mangling is toÂ
refrain its accidental usage from Java. Kotlin usages are type-safe, youÂ
can only pass the correct type. But if you use it from Java, you can have the sameÂ
confusion problems as when using primitive types. To prevent them, both theseÂ
invocations donât compile in Java. When the function name is mangled,Â
you no longer can call it from Java. Java sees only the mangled name but canâtÂ
call it because itâs not a valid identifier. If you wanna use a function taking an inlineÂ
value class argument from Java, use a workaround. You can provide an explicitÂ
JvmName for this function. That changes the underlying name in the bytecode  and makes it visible by thisÂ
name and usable from Java. I wanna point out one peculiarity ofÂ
defining inline classes in the library. Imagine youâre a library author and you defineÂ
an inline class as a part of the public API. If you wanna later change theÂ
type of the underlying value, itâs a breaking change!
Since any function using  this inline class is compiled to the oneÂ
using the underlying type, that breaks! Thatâs what happens with Duration,  and that demonstrates why itÂ
wasnât a part of the stable API. Such change is a breaking change. We do want to stabilize thisÂ
functionality soon, but as always,  we need your help to battle-test it.
Please share your feedback and your use-cases! If you follow the language changesÂ
and were using inline classes before, you might be surprised, why the syntax changes. It was âinline classâ before, but now itâs âvalueÂ
classâ annotated with the @JvmInline annotation. Why? The term inline class turned out toÂ
be a bit confusing with inline functions. Some might expect that all membersÂ
of the inline class are inlined,  which is not the case.
Or one could think that an  inline class will always be replaced with theÂ
underlying value, which is also not correct. Whatâs important, Inline classes nowÂ
become a part of the bigger story:Â Â a case of a value class withÂ
the specific optimization. You donât need to know these detailsÂ
to use the new syntax right now. But if you wanna learn more about value classes,  please watch a separate video about this plannedÂ
functionality. Should be linked somewhere (here). If you wanna learn more detailsÂ
about inline value classes please check the description inÂ
our blog and in the documentation. Thank you for your attention, and letâs Kotlin!
How can this be stable before Valhalla?
About time inline classes left experimental.
Just got one question. Is that
@JVMInline
required, and if so.. why? Can't the kotlin compiler deduce that from thevalue class
?