avva: (Default)
[personal profile] avva
(эта запись может быть интересна разве что программистам)

Прочитал Java Generics FAQ. 500 страниц, между прочим, в PDF-версии. 500 страниц. Когда вы в последний раз читали FAQ на 500 страниц? Ну вот и я тогда же. С трудом верится даже теперь, по прочтении. Правда, там много места занимают бесконечные индексы и оглавления и заголовки, так что реально "мяса" страниц на 350. Но и этого довольно.

Теперь я понимаю, зачем в Джаве класс Enum определяется, как Enum<E extends Enum<E>>, что это в точности значит, и зачем это нужно. Не уверен, что мне нравится, что я это теперь понимаю.

Многие объяснения в этом фэке читаются, как один сплошной WTF. Ты понимаешь, в процессе чтения, почему это сделано так, а не иначе. Почему и тут исключение, и тут, и это надо делать через задницу, а то даже через задницу не сделать. Почему - один пример наугад из сотни - все обычные вещи с параметризованными типами можно делать, а вот создавать массивы из них нельзя. Кроме случая, когда они параметризованы неограниченными вопросиками. Ты понимаешь, почему это так получается, но не оставляет ощущение глубокого WTF на тему того, как мучительно и болезненно эти дженерики врастают в плоть языка. Сказать, что это leaky abstraction - ничего не сказать; эта лодка не протекает, она буквально состоит из воды.

Вот один из прекрасных вопросов из этого FAQ:
What is the difference between a Collection<Pair<String,Object>>, a Collection<Pair<String,?>> and a Collection<? extends Pair<String,?>>?
Ответ начинается так: "All three types refer to collections that hold pairs where the first part is a String and the second part is of an arbitrary type. The differences are subtle." Потом на двух страницах объясняются эти subtle differences.

По-моему, внесение дженериков в Джаву было огромной ошибкой. Главная польза от них - строгая типизация коллекций - не оправдывает той огромной цены, которую пришлось заплатить: сложностью языка, читабельностью и понимабельностью кода. Учитывая то, что динамическая безопасность у коллекций и так была, необходимость безопасности на уровне компиляции была кем-то, по-видимому, сильно преувеличена. Да, конечно, намного удобнее и проще написать ArrayList<String>, и знать, что попытка всунуть туда что-то другое вообще не скомпилируется. Это удобнее, чем всунуть что-то не то в ArrayList и получить исключение в рантайме, когда это взяли и попытались привести к String. Баги ловятся быстрее. Но насколько быстрее, как часто на практике это оказывалось существенным, и оправдывает ли эта польза введение архитектуры, приводящей к Enum<E extends Enum<E>> или вопросам, подобным процитированному выше?

Одним из главных преимуществ Джавы по сравнению с C++ было именно grokability исходного кода средним программистом: посмотрев на исходник какого-то класса, который он раньше не видел, средний программист на Джаве - не гуру, не хватающий звезды с неба итд. - мог сказать, что делает каждая строка и зачем это нужно. Дженерики это свойство языка с помпой похоронили. Кто были люди, которые приняли решение так поступить, и радовались ли они красивому трюку само-референтных типов? И это только ущерб понятности кода, не говоря о всем этом огромном числе исключений и плохой совместимости с существующими частями языка - массивами, рефлекцией, исключениями, итд. итд. итд.

Можно ли было добиться той же пользы, что дали дженерики, менее разрушительными способами? Пусть не той же, но главной ее части, мне кажется, можно было. Скажем, какая-нибудь аннотация в момент создания коллекции, подсказывающая компилятору, что там должно быть. Просто сказать: в эту коллекцию я хочу класть строки, или такие-то пары, итп. И пусть компилятор проверяет, что сможет, и вставляет эксплицитное приведение к строкам или парам, когда мы из коллекции что-то достаем. И все. Без extends, без wildcards, для всех мест, где это действительно надо, пусть программист продолжает приводить эксплицитно. Конечно, такая аннотация не покрыла бы все случаи, но самые простые и важные, думаю, покрыла бы. Главное ведь то, что у дженериков почти нулевой эффект на рантайм, поэтому необязательно было вносить их глубоко в ткань языка, so to speak; подсказки компилятору достигают схожей цели. Простая (простая!) и удобная подсказка захватила бы, мне кажется, большинство багов с типами в коллекцях, которые до дженериков проявлялись только в рантайме.

(disclaimer: я редко и мало пишу на Джаве, и не эксперт в ней)

Date: 2010-05-22 04:04 am (UTC)
From: [identity profile] selfmade.livejournal.com
Может я чего-нибудь не понимаю, но почему бы не взять красивые и приятные в использовании дженерики из C#?
Дженерики появились в C# раньше, чем в Java, хотя первые версии C# были частично слизаны с Java. С тех пор C# шагнул сильно вперёд. Теперь очередь Java слизывать.

Date: 2010-05-22 07:46 am (UTC)
From: [identity profile] avva.livejournal.com
Я их просто не знаю, как и сам C#. На вопрос "почему нет" подозреваю, что ответ "слишком сложно, или не хочется из соображений совместимости, делать нужные изменения на уровне JVM". Джавовские дженерики вообще не требуют изменений на этом уровне.

Date: 2010-05-23 05:27 am (UTC)
From: [identity profile] selfmade.livejournal.com
JVM я не знаю, но подозреваю, что способ найти можно было бы. Например, пусть разработчик пишет List<T> а оно внутри преобразует эту красоту в их текущее безобразие. А Func<T> - во внутренний класс с одним методом.

Date: 2010-05-22 11:22 am (UTC)
From: [identity profile] ilyabo.livejournal.com
В C# дженерики лучше получилось, потому что их с самого начала добавили. А в джаве, если я правильно понимаю, хотели чтобы можно было безболезненно обобщать legacy code. В частности, библиотека коллекций уже была, поэтому нужно было выбирать между добавлением параллельной библиотеки с дженериками или erasure. Выбрали второе как наименьшее из зол.

Date: 2010-05-22 01:06 pm (UTC)
From: [identity profile] migmit.vox.com (from livejournal.com)
> Выбрали второе как наименьшее из зол.

И ошиблись, ИМХО.

Date: 2010-05-22 07:12 pm (UTC)
From: [identity profile] ilyabo.livejournal.com
а вы представляете, что бы было, если бы в джаве одновременно были две несовместимых стандартных библиотеки коллекций?

Date: 2010-05-22 09:32 pm (UTC)
From: [identity profile] migmit.vox.com (from livejournal.com)
Да, представляю. Длинный переходный период. Но он бы закончился. Уже сейчас о нём бы только вспоминали. Вместо этого мы получили язык, в котором дофигищи острых углов, и так оно и останется.

Date: 2010-05-25 08:11 am (UTC)
From: [identity profile] skipy-ru.livejournal.com
Вы пребываете в иллюзии. ОЧЕНЬ большая часть библиотек общего назначения все еще не переписана под версию 5. Вариантов два - или писать самому, или ждать, пока перепишут авторы. Если перепишут. И перепишут ли так, как надо? Прецеденты были - я лично использовал библиотеку, написанную под 1.4, то, что сделали при миграции на 1.5, использовать невозможно. Авторы убили всё то, из-за чего я эту библиотеку использовал. Стоимость написания подобного фреймворка самому - несколько человеко-лет.

Имхо, вариант несовместимости привел бы к тому, что все продолжали бы сидеть на 1.4. ОЧЕНЬ долго.

Date: 2010-05-25 08:34 am (UTC)
From: [identity profile] migmit.vox.com (from livejournal.com)
> ОЧЕНЬ большая часть библиотек общего назначения все еще не переписана под версию 5.

Ну вот, внизу говорят, что опыт шарпа свидетельствует об обратном.

Date: 2010-05-25 09:43 am (UTC)
From: [identity profile] skipy-ru.livejournal.com
А можно поинтересоваться - сколько к этому моменту было написано на шарпе? Промышленных приложений, не на коленке.

С момента выхода Java5 прошло уже больше 6 лет, собственно, 5-я версия уже не поддерживается. И тем не менее ОЧЕНЬ много библиотек на нее все еще не переведено. Посмотрите ради интереса на Apache Commons. И представьте, насколько широко эти библиотеки используются.

А ведь есть не только библиотеки. Apache Geronimo - он же IBM WebSphere Application Server CE - получил поддержку Java5 только с версии 2.0, в 1.1 он работал на 1.4. А версия 2.0 вышла где-то с год назад, у нас к этому времени уже в промышленной эксплуатации система была на 1.1 и Java5.

Date: 2010-05-25 09:48 am (UTC)
From: [identity profile] migmit.vox.com (from livejournal.com)
> А можно поинтересоваться - сколько к этому моменту было написано на шарпе?

Можно, но не у меня.

Date: 2010-09-30 09:19 pm (UTC)
From: [identity profile] intracer.livejournal.com
http://archive.eu.apache.org/dist/geronimo/2.0/

Geronimo 2.0 вышел в августе 2007 и поддерживал J2EE 5.0

Без поддержки Corba и Geronimo 1.1 работал на JDK 5 (Хинт - JDK (JavaSE) != JavaEE)

Date: 2010-05-24 09:47 am (UTC)
From: [identity profile] plakhov.livejournal.com
Представить несложно, в C# так и было.
Не такой уж и хаос, как можно было бы предположить.

Date: 2010-09-30 09:08 pm (UTC)
From: [identity profile] intracer.livejournal.com
Дженерики в Java - J2SE 5.0 (September 30, 2004)
Дженерики в C# - C# 2.0 November 2005

December 2025

S M T W T F S
  123 4 56
78 9 10 11 1213
1415 1617181920
21 22 23 24 2526 27
28293031   

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Dec. 29th, 2025 08:25 pm
Powered by Dreamwidth Studios