С выходом Kotlin 1.5.0, классы значения (известные ранее как inline классы) наконец-таки стабильны и были освобождены от аннотации @OptIn. Было много нового в релизе, что также создало много путаницы, так как теперь нам доступны три очень похожих инструмента: псевдонимы типов, классы данных и  классы значения. Так какой же нам использовать теперь? Можно ли выбросить сразу псевдонимы типов и data-классы и заменить их на value-классы? Классы в Kotlin решают две проблемы: Они передают смысл через их название и облегчают понимание, что за объект передается. Они принуждают к типобезопасности утверждая, что объект класса А не может быть передан функции, которая ожидает объект класса Б входным параметром. Это предотвращает серьезные ошибки еще во время компиляции. Примитивные типы такие как Int, Boolean, Double  также принуждают к типобезопасности (нельзя передать Double туда, где ожидается Boolean), но они не передают смысл (ну кроме того, что это число). Double числом может быть практически что угодно: температура в градусах Цельсия, вес в килограммах или уровень яркости вашего экрана в процентах. Все что понятно это только то, что мы имеем дело с числом с плавающей запятой двойной точности (64 бит), но это не говорит нам о том, что это число собой представляет. По этой причине, семантическая типобезопасность нарушена: Если у нас есть функция для установки уровня яркости нашего дисплея: мы можем вызвать эту функцию с любым Double значением и можем случайно передать число с совершенно другим смыслом: Компилятор такое пропустит, но это программная ошибка, которая может и "уронить" программу или , что даже хуже, к неожиданному поведению. Есть несколько подходов к решению двух вышеупомянутых проблем. Можно просто обернуть примитивный тип классом, но это влечёт много издержек. Итак, давайте посмотрим как мы можем победить эти проблемы с помощью: класса данных; псевдонимом типа; и класса значения. и исследуем какой из этих способов наиболее целесообразный. Самым простым путем (присутствующим изначально в Kotlin) будет использование класса данных: DisplayBrightness здесь - тип сам содержит Double, но несовместим по присваиванию с Double (например, setDisplayBrightness(DisplayBrightness(0.5)) будет работать, но setDisplayBrightness(0.5) даст ошибку компиляции). Также это решение все еще позволяет сделать так: setDisplayBrightness(DisplayBrightness(person.weight)) . Очевидно, что решение - такое себе. Однако, есть один огромный минус: инстанциирование классов данных очень дорогое. Примитивные значения могут быть записаны в стек, который быстрее и эффективнее. Экземпляры классов данных записываются в кучу, что требует больше времени и памяти.Вы спросите: на сколько больше времени? Давайте протестируем: ...дает вывод: И хотя этот удар по производительности и кажется незначительным для современных очень очень быстрых электронно-вычислительных машин, такие небольшие улучшения играют большую роль в приложениях, требовательных к производительности. Псевдоним типа дает второе имя для типа. Например: Под капотом, Double и DisplayBrightness стали синонимами.Теперь, когда компилятор видит DisplayBrightness он просто заменяет это на Double и двигается дальше. Соответственно, новый псевдоним DisplayBrightness работает также быстро как и Double - он использует те же оптимизации, что и Double.Если мы расширим приведенный ранее тест, мы увидим, что и для синонима и для примитивного типа тест займет примерно тоже самое время: Так как DisplayBrightness это синоним Double - все операции, которые работают с Double, также работают и с DisplayBrightness: Подвох этого в том, что DisplayBrightness и Double теперь совместимы по присваиванию, и значит компилятор радостно примет это: Так решили ли мы проблему на самом деле? Что же, отчасти. Тогда как псевдонимы типов делают сигнатуры функций более выразительными и намного быстрее классов данных, тот факт, что DisplayBrightness и Double совместимы по присваиванию оставляет проблему типобезопасности нерешённой. На первый взгляд, классы значения очень похожи на классы данных. Их сигнатура выглядит в точности одинаково, только вместо data class ключевое слово value class : Также, вы можете заметить @JvmInlineаннотацию. KEEP о классах значения объясняет это, а также причину того, что классы значений могут иметь только 1 поле на данный момент. Вкратце, тогда как Kotlin/Native и Kotlin/JS  бэкенды технически могут поддерживать классы значения с больше чем одним полем, Kotlin/JVM на данный момент - нет. Это из-за того, что JVM поддерживает только её встроенные примитивные типы. Однако, есть планы и проект Valhalla (смотри соответствующий JEP), который позволит пользовательские примитивные типы. Дело обстоит сейчас так, что команда Kotlin полагает, что проект Valhalla - лучшая стратегия компиляции для классов значения. Однако, проект Valhalla еще не стабилен, и им было нужно найти временную стратегию компиляции, на которую можно было бы положиться. Для того, чтобы сделать это явным, на данный момент @JvmInline- вынужденная мера. За сценой, компилятор считает классы значения псевдонимом типа, но с одним большим отличием: Классы значения несовместимы по присваиванию, и это значит, что следующий код не скомпилируется: Расширив приведенный выше тест, мы увидим, что классы значений имеют такую же высокую производительность, как и примитивные типы и, таким образом, как и псевдонимы типа: Итак, кажется, что классы значений проставили все галочки, так? Они... Делают объявление переменных и сигнатуры функций более выразительными, ✅ Сохраняют производительность примитивных типов, ✅ Несовместимы по присваиванию с их базовым типом, предотвращая пользователя от совершения глупых вещей, ✅ и поддерживают множество особенностей классов данных, таких как конструкторы, init, методы и даже дополнительные свойства (но только через геттеры). ✅ Единственное оставшееся применение для классов данных - это когда вам нужно обернуть несколько параметров. Классы значения ограничены одним параметром в их конструкторе на данный момент. Аналогично, псевдонимы типа все еще имеют свои применения, которые не могут быть покрыты классами значения (или идут в разрез с их предназначением): Сокращение длинных сигнатур обобщенных типов: Параметры функций высшего порядка: За исключением этих исключений, классы значений действительно являются лучшим решением в большинстве случаев. (По этой причине, мы сейчас переводим наши проекты на классы значения.) Есть два документа, которые действительно помогут нам понять как работают классы значения и какие инженерные идеи возникли в процессе дизайна: документация соответствующий KEEP Также в KEEP рассказано о возможных будущих разработках и идеях дизайна. Эта статья на typealias.com объясняет как псевдонимы типа работают и как они должны использоваться - рекомендуется к прочтению. Если же вам интересна разработка языка Kotlin в целом, может быть вам понравится статья Kotlin’s Sealed Interfaces & The Hole in The Sealing. Спасибо за внимание!  Software Architect