From Inline to Value Classes

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

How can this be stable before Valhalla?

👍︎︎ 3 👤︎︎ u/fanfan64 📅︎︎ Apr 26 2021 🗫︎ replies

About time inline classes left experimental.

👍︎︎ 1 👤︎︎ u/dstibbe 📅︎︎ Apr 26 2021 🗫︎ replies

Just got one question. Is that @JVMInline required, and if so.. why? Can't the kotlin compiler deduce that from the value class?

👍︎︎ 1 👤︎︎ u/0xVali__ 📅︎︎ Apr 26 2021 🗫︎ replies
Captions
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!
Info
Channel: Kotlin by JetBrains
Views: 8,947
Rating: 4.94382 out of 5
Keywords: Kotlin, inline class, value class, duration, Svetlana Isakova, Kotlin 1.5, Kotlin 1.5.0, Kotlin Release, Kotlin 1.5 Release, Kotlin 1.5.0 Release
Id: LpqvtgibbsQ
Channel Id: undefined
Length: 11min 28sec (688 seconds)
Published: Sat Apr 24 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.