Типы-значения в Java

Этот пост — вольно-краткий перевод документа State of the Values, предложения по введению типов-значений в JVM и сам язык Java, который написали Джон Роуз, Брайан Гоетц и Гай Стил, разбавленный моими мыслями. Опущены детали предложения по реализации типов-значений на уровне байт-кода, что не очень интересно для большинства Java-программистов.Важнейшая мысль: объектная (ссылочная) идентичность нужна только для поддержки изменяемости объектов. Объект может изменить состояние, но по ссылке мы всегда можем проверить, что это «тот же» объект. Поэтому типы-значения будут строго неизменяемые.Предполагаемые варианты использования типов-значений:

Числа: комплексные, беззнаковые, 128-битные, с фиксированной запятой и т. д. Все, что не описывается имеющимися примитивами. Алгебраические типы: Optional, Choice, перечисления (enum) Кортежи (пары, тройки, …) Итераторы, курсоры Кортежи (пары, тройки, …) «Уплощение» сложных структур. Целевые фичи: Можно использовать типы-значения везде, где сейчас можно объекты и примитивы: локальные переменные, поля, элементы массива, аргументы методов. В обычной ситуации аллокация в регистрах, на стеке, поле-значение это не ссылка, а прямо байты полей в родительском объекте. Хотя у ВМ есть право таки создать значение в куче, напр. если она считает, что так будет лучше, не может иначе обеспечить атомарность, не хватает стека, и т. д. Массивы с элементами типа-значения должны быть «плоскими». При необходимости (напр. при передаче в метод, который хочет Object) неявные приведение (boxing) к обычному объекту-двойнику (как сейчас с примитивами). Не просто структурки с полями: можно объявлять методы как в обычном объекте, переопределять equals (), toString (). Вызов метода не (обязательно) приводит к приведению к обычному объекту. Инкапсуляция полей возможна. Компилятор или ВМ генерирует equals (), hashCode (), toString (), compareTo () по полям, если не переопределены в коде. Типы-значения сами (а не только их «обычные» объектные двойники) могут реализовывать интерфейсы. Т. е. передача в метод, который хочет, допустим, Comparable не обязательно приводит к оборачиванию значения в объект. Можно объявлять поля типа-значения как volatile. Типы-значения могут содержать и обычные объектные поля (которые не обязаны быть рекурсивно неизменяемыми, как сами значения), и поля других типов-значений. Но: не могут содержать поля своего же типа. Ограничения (должно быть запрещено или вызывать оборачивание в объект-двойник):

Тип-значение не может наследовать ни классу, ни другому типу-значению, от типа-значения ничего нельзя наследовать. (Хотя, возможно, будет возможность наследовать от «чисто абстрактных» классов, например от java.lang.Number.) Вызов wait (), notify (), clone () или finalize () на значении. Вызов System.identityHashCode () к значению. Присвоение переменной типа-значения null. Приведение к Object или любому супертипу. Применение рефлексии к значению. Запарки с атомарностью (напр. на платформе нельзя обеспечить атомарность чтения/записи, если общий размер типа-значения больше машинного слова, или двойного слова). Синтаксис Объявление типа-значения максимально приближено к обычным классам: final __ByValue class Point { public final int x; public final int y;

public Point (int x, int y) { this.x = x; this.y = y; }

public boolean equals (Point that) { return this.x == that.x && this.y == that.y; } } Уродливое __ByValue специально для того, чтобы никто не воспринимал это как окончательный синтаксис. Может, будет аннотация типа @ValueType. Объявление полей финальными — либо обязательно, либо неявное, как сейчас методы в интерфейсах можно объявить без public, но они все равно будут публичными. То же касается и модификатора класса.Создание значения:

Point p = __MakeValue (x, y); Тут вместо __MakeValue будет либо название типа без new, либо ничего, т. е. создание значения — просто скобочки с аргументами.Поддержки специальных литералов (типа 0 + 1i для комплексных чисел или 1u для беззнаковых), а также перегрузки операторов (что было бы полезно тоже в первую очередь для числовых типов), скорее всего, не будет.

Надо понимать, что массивы, java.lang.String, java.lang.Integer и т. д. для бинарной совместимости в типы-значения преобразованы не будут. Так что существующий код магически не ускорится. По крайней мере, не в разы. Внутренний тип java.util.HashMap.Entry, например, поменять вполне могут.

Возможно, сделают отдельную сущность для массивов-значений, которые могут заменить varargs на уровне языка.

Объект Значение Содержит что-то разное Объект Типы-значения Одинаковое Массивы Массивы-значения? Generics Самый важный вопрос. В текущем виде дженерики — фича времени компиляции, и никаких типов-значений они поддерживать не будут. Но раз уж сказал «А» (типы-значения), то говори и «Б», поэтому рано или поздно дженерики переделают.Мой прогноз:

Для Java 9 уже есть одна «главная» фича — модуляризация, Oracle явно делает на нее ставку, вероятность увидеть ее в Java 9 близка к 100%. Если в Java 9 дженерики оставят «как есть», шанс увидеть типы-значения в этой версии 30%. Если решат выкатить типы-значения и обновленные дженерики одновременно, в лучшем случае это случится в Java 10. Я знаю, этот блог читает много сотрудников Oracle, которые куда внимательнее следят за списками рассылки и вообще ближе к теме, буду рад если они внесут важные уточнения.

© Habrahabr.ru