Pull to refresh
75
-1
Alexey Andreev @konsoletyper

Пользователь

Send message

Ну а толку-то? По сути, не нужен для этого никакой цикл. Это будет эквивалентно какому-нибудь if..else if… else. На уровне синтаксиса это можно подсахарить. Вон, в Kotlin есть when, который по сути является сахаром для if..else if. Но чуда не ждите, на рантайме от этого быстрее не станет. Когда в Java 7 вводили switch по строкам, задизайнили фичу так, чтобы её можно было эффективно реализовать.

Я так понимаю, это всё-таки не документируется в спеке языка. Т.е. компилятор может реализовывать switch по строкам в принципе как ему захочется. А вот в JDK это поведение чётко описано. Просто так особенности реализации в javadoc-ах не описывают, т.е. именно такой способ вычисления String.hashCode — это всё-таки публичный контракт. Учитывая особенности публичного контракта JDK, компилятор может порождать эффективную реализацию (что и делает javac).

Что "делается"? Инстанс объекта создаётся? Нет, ничего не создаётся, но вычисление hashCode требует знания, какое у объекта внутреннее состояния. Без знания логики конструирования объекта о внутреннем состоянии судить нельзя, следовательно невозможно вычислить hashCode.


Зачем компилятору вычислять hashCode? А как он сгенерит такое:


switch (str.hashCode()) {
    case FOO_HASHCODE: if (o.equals("foo")) { ... } else goto default;
    case BAR_HASHCODE: if (o.equals("bar")) { ... } else goto default;
    default: { ... }
}

Ну хорошо, мы можем и дальше так продолжать играть в вопросы. Давайте так, если есть что предложить — предлагайте (и даже можете кинуть JSR в JCP). Только не в духе "хорошо было бы сделать", а в духе "как ИМЕННО сделать" с учётом разных нюансов. Я уверяю, при попытке сформулировать предложение вы сами всё поймёте.

Отсутствие в компиляторе знания о том, как именно в этих объектах реализован hashCode. Отсутствие знания в компиляторе о том, как именно сконструировать экземпляр объекта в compile-time. Для частных случаев (например, строки, enum-ы) это знание есть.

Внутри case будет цепочка if/else if, где с помощью equals проверяется каждый вариант.

Её менять нельзя из-за того, что в java 7 появился switch по строкам. А он как раз реализован через switch (str.hashCode()), и компилятор вставляет предвычисленные хэш-коды прямо в байт-код.

Глупые, детские хотелки. Язык — это очень серьёзный проект, такое не пилится школотой во время каникул!

Это да, вот только помимо языка (парсер, семантический анализатор, библиотеки, дизайн), ещё есть рантайм, а это тоже куча человеко-лет. Причём, ещё непонятно, что из указанного требует больше времени на разработку. Скажем, написать хороший оптимизатор, хороший JIT, хороший GC — та ещё задача.


Ясно. В третьем классе детям рассказали про ЯП.

Исходный тезис немного громкий, но давайте не кидаться какашками. Просто есть платформа JVM, для неё можно писать языки (и люди пишут), и действительно, эти языки прекрасно работают с существующим кодом, написанным на Java.


Да зачем?? Причём тут вообще «язык» и все эти дебри из мира виртуальных машин? Кто вообще сказал, что нам нужна VM?!!!

Какие такие дебри. JIT и AOT — это всего лишь про рантайм. C++ обычно реализуется в виде AOT-компиляторов, Java — JIT, но может быть и наоборот (те же Excelsior JET — пример Java, компилирующейся AOT). И вообще, понятие VM — это достаточно расплывчатая штука. Вот есть какой-то IR у компилятора. Можно ли интерпретатор этого IR назвать VM? А AOT-компилятор в нативный код? А JIT? Что такое LLVM (у которого две последние буквы VM)? Таки VM или компиляторный бэкэнд? Почему GCC не содержит в себе буковки VM, хотя на деле он очень похож на LLVM?


Бред сивой кобылы. Таких «задач» — две на мильён, с какого перепугу нам в языке это нужно??

В языке это не нужно. Это нужно в рантайме. А нужно это с целью добиться лучшей производительности кода, написанного на языке. За счёт hot swap можно прямо во время исполнения собрать профиль и на основе профиля скомпилировать код более эффективно и заменить старую версию на новую.


Да нифига не хотим! Много из вас «накоммитило» в гитхабы? Единицы по десятку строк. Так зачем вам исходники, в которых вы всё равно ни черта не понимаете??

Это на уровне энтузиастов так. А на уровне компаний может быть иначе. Компании может стать интересен какой-то opensource-проект, и она может специально людей набрать, которые будут сидеть на з/п и в этот проект контрибьютить. Со всякими Linux и JVM примерно так дела и обстоят.


рисовать в небе пони и насиловать JVM в жалких попытках реванша перед .NET;

Это какой такой реванш перед .NET? Как бы мы живём в мире, где .NET всё ещё не убил Java, и вроде бы не собирается убивать. Наоборот, судя по объявлениям о работе у Java дела намного лучше идут. Если кто и убьёт Java (вместе с .NET в придачу), то какой-нибудь JavaScript, но мы же будем верить в лучшее, и понадеемся, что этого не произойдёт?

А вот если код «писан индусами», не понимающими что, как и где вообще происходит (знаменитое «к пуговицам претенции есть?»), вот тогда — с GC всё будет тормозить и жрать память, как не в себя, а без GC — вообще развалится к чертям собачьим.

Есть одна контора, где код, видимо, писан индусами (хотя почему-то основной офис у них в Санкт-Петербурге). Только вопрос: а есть ли в природе хоть одна такая же крутая IDE, написанная крутыми мужиками на C++? Ах да, IDE крутым парням не нужны, vim хватает всем, а IDE — это костыль для индусов, которые не понимают, что они пишут.

Так давайте определимся, уплотняющий GC или нет. А то получается, что преимущества приводятся для их объединения.

В современных рантаймах GC уплотняющие, и это подаётся как преимущество, а не как недостаток, вопреки тому, что уплотнение даёт оверхед.


А откуда вообще следует, что она, ну, есть? Ведь для пространственной локальности необходимо, чтобы, условно, следующий объект в памяти, к которому вы обращаетесь, лежал в вашем кешлайне. Как это связано с компактифицирующим GC?

Собственно, причины две. Во-первых, в survival space объекты будут лежать кучно, и они могут взять и влезть в кэш. Во-вторых, при выделении памяти в eden space она будет всегда выделяться строго последовательно, а не в дырках.


С generational GC, да, связано, но не с компактифицирующим.

А поколения тут при чём? Поколения нужны, чтобы уменьшить паузы и увеличить пропускную способность за счёт обхода только подмножества графа. Или я что-то не понимаю?


В вышеупомянутом подходе их вообще нет.

Это понятно, что в определённых ситуациях можно вручную управлять памятью эффективнее, чем GC. Но во-первых, это отнюдь не те пресловутые 95% ПО, а во-вторых, это не всегда даёт достаточный выигрыш, чтобы оправдать увеличение стоимости разработки.


Так, иногда и компиляторы идут лесом и код, написанный вручную на ассемблере, оказывается быстрее. Например, интерпретатор Java-байткода за счёт грамотного распределения регистров аж в 2 раза быстрее работает, если его написать на ассемблере. Но в большинстве случаев компилятор тупо умнее программиста.

И при уплотнении тоже никакого оверхеда?

При уплотнении есть оверхед. Другое дело, что GC не обязательно должен быть уплотняющим. Но уж так сложилось, что для передовых рантаймов пишут уплотняющие GC, наверное, практика показала, что они эффективнее. Потому что так аллокация сильно дешевле (по сути — обычный инкремент), и потому что расходы на уплотнение компенсируются выигрышами от пространственной локальности.


Никаких локов, ничего, не нужно оно там. GC правда может эффективнее?

Кстати, я где-то видел презентацию, где в Graal добавили region-based memory management, и не получили ощутимого прироста производительности. GC не может эффективнее, но может в ряде случаев приближаться по эффективности. По крайней мере, аллокация и освобождение столь же дешёвые, минус расходы на обход графа объектов.

А почему, собственно? Фактически это — те самые арены, которые так не любят некоторые.
Многолетний многомиллиардный эксперимент с Java/.NET — в общем и целом, провалился.

Пожалуйста, не пишите глупости, не позорьтесь, если не разбираетесь в предметной области.

Ну так это сравнение между ручным и автоматическим управлением памятью. Подсчёт ссылок — это тоже вид автоматического управления памятью. И с ним у них был бы подобный оверхед по памяти. И вызван он был не GC, а тем, как представлены строки в CLR. А мой вопрос стоял не относительно памяти, а относительно влияния трассирующего уплотняющего GC на (пространственную) локальность, и как следствие — на производительность.

Вы хотите сказать что для языков с GC над этим думать не нужно? А для чего тогда целые библиотеки подобные Guice создают?

Ну это вообще никак не относится к управлению ресурсами. Это DI-контейнер, нужный для облегчения реализации паттерна IoC, а уж зачем он — это вопрос архитектурный (позволяет грамотнее распределить отвественность между компонентами приложения), и никак к управлению памятью не относится.


А тогда о чём мы вообще спорим?

Ну я где-то читал (точно не помню, но по-моему, это была последняя редакция dragon book), что уплотняющий GC даёт лучшую локальность, чем компенсируется его оверхед. Сейчас конкретных ссылок на конкретные исследования дать не могу.


О как. То есть для того, чтобы GC «проявил себя» нужно отказаться от использования наработанных библиотек, инструментов и прочего и, грубо говоря, начать жизнь «с чистого листа».

Это так для legacy-мира. Но тем же Java и JS по 20 лет, .NET — 15 лет. Для них за это время написана целая куча библиотек, инструментов и "прочего". Опять же, есть средства интеропа нативных библиотек с управляемыми рантаймами. И да, разработчики обёрток, которые для managed-рантаймов заворачивают библиотеки, должны думать о явном освобождении ресурсов. Но 1) разработчики приложений об этом уже не думают 2) постепенно старые нативные библиотеки переписывают под новый рантайм.

Это с какого перепугу? Какие-такие накладные расходы при использовании какогого-нибудь unique_ptr?

Ну всё-таки давайте будем честны, всю программу на одних только unique_ptr не напишешь. Плюс возникают накладные расходы на создание программы (думать, кто каким объектом владеет). А так, для общего случая нужен указатель с подсчётом ссылок, который добавляет оверхед.


Что, с GC у вас ресурсы утегать не будут? Будут, ещё как будут, если вы запутаетесь в том кто и когда ими владеет.

Будут, но достаточно редко.


Иначе бы подобные ужасы были бы не нужны.

Эти ужасы только в узком слое интеропа с нативной библиотекой UI.


Какое, блин, достижение. А в цифрах — не, не покажите? Что именно вам это даёт? И как часто? С точки зрения конечного пользователя, пожалуйста.

Даёт лучшее попадание данных в кэш. Это, конечно, теоретически, а практически — надо смотреть конкретные ситуации. Мы тут вообще-то холиварим в комментах, а не ведём серьёзную научную дискуссию, поэтому ссылок на конкретные исследования не будет. Могу лишь предложить поделиться ссылкой, которая опровергает мой тезис, т.е. показывает конкретные бенчмарки, где существенного прироста производительности из-за локальности данных, обеспеченных уплотняющим GC, не обнаружено (по сравнению с каким-нибудь dlmalloc).


Всё как раз наборот. Иначе вот этого бы не было. Поверьте — у Apple есть много недостатков, но умения создать красивые, приятные в работе, программы — у них не отнять. И вот для них — GC противопоказан.

Вот это как раз весьма и весьма спорное утверждение. Я так понимаю, вопрос memory management решался ещё во времена objective C, который является по сути макронадстройкой над C, т.е. требуется поддерживать семантику C, которая не предполагает наличие специальным образом сделанного рантайма. Отсюда, единственным возможным выбором для Objective C является консервативный GC, который, как известно, не умеет инкрементальной и параллельной сборки, т.е. тормозит.

Речь же о том, почему используется GC, а не смарты? GC заявляется панацеей от необходимости контролировать время жизни объектов. При этом несет много проблем с собой. Смарты тоже убирают проблему контроля времени жизни. При этом дают минимальные накладные расходы и не требуют выполнения в фоне дополнительных плохо контролируемых процессов.

Например, потому, что GC всё-таки даёт ощутимо меньшие накладные расходы, чем смартпоинтеры, в том числе по памяти (GC не требуют тащить дополнительные 32 бита на объект для счётчика). Особенно в многопоточном коде. А ещё у смартпоинтеров проблема с циклическими ссылками. А ещё GC уплотняют кучу, этим улучшая локальность доступа к памяти (знаю, современные алгоритмы malloc умеют частично решать проблему фрагментации памяти, но ключевое слово — частично).


В итоге, счётчик ссылок лучше подходит только в достаточно узкой нише, там где очень важно детерминированное время задержки, это всякая кровавая эмбедщина или кровавый хайлоад с каком-нибудь высокочастотном трейдинге. Для остальных задач, коих тьма, GC подходит лучше. Кстати, существуют специализированные GC, которые ценой определённых накладных расходов умеют сильно снижать время задержки. Гуглить например metronome GC.

Как раз Common Lisp — это плохой пример. В нём ровно две фатальные проблемы: динамическая типизация и макросы. Именно они делают код на CL совершенно нечитаемым и трудноподдерживаемым, уж не говоря о его минималистичном синтаксисе.

Когда я читаю статьи Егора, мне вспоминается мультфильм про зайца, который всех учил чему-то. Сороконожка нормально ходила, никогда не задумываясь, как ходить, но как только начала ходить "правильно", оказалось, что она вообще не может ходить!


А всё потому, что он приводит короткие красивые примеры, где всё выглядит хорошо, но на практике, когда система начинает усложняться, писать, как он предписывает — равносильно самоубийству. Примеры? Пожалуйста (спасибо одному из комментаторов, дал хорошую подборку):


3) Data Transfer Object Is a Shame
«DTO плохо» взамен предлагается переложить сериализацию/десериализацию на саму сущность, минуя DTO

Да, вот только есть ещё такой подход, как single responsibility principle, такой важный, что является частью SOLID, и статьи, расписывающие преимущества SOLID, не менее логичны, чем статьи Егора. Вот только практика (именно практика, а не маленькие игрушечные примеры) показывает, что SOLID работает, а подходы Егора — нет.


Другой пример — Егор предлагает заменять utlity-методы объектами, т.е. вместо CollectionUtils.sort делать класс SortedList, и сортировать список, создавая экземпляр этого класса. Я не вижу никакой разницы, т.к. всё равно ничего не инкапсулируется, и более того, конструктор — это фактически и есть вызов статического метода (называемого <init>). Ну а уж по поводу критических по производительности кусках кода я вообще промолчу.


Так вот, проблема в том, что действительно, приходится писать не самые "чистые" вещи в коде. И это проблема не глупых разработчиков, это проблема глупых средств разработки. Были бы языки программирования повыразительнее, можно было бы включить перфекционизм на 142% и писать бескомпромиссно чистый код. Однако, тут проблема в том, что излишне выразительные языки программирования обладают тем недостатком, что их сложно выучить и сложно эффективно реализовать компиляторы и тулинг, но что ещё важнее, — они слишком непредсказуемые.

Я уже писал чуть выше, почему есть смысл писать на GWT, а не на JS. Незнание JS — это не причина использовать GWT, но зато за использование GWT есть много других причин.

Вместо того, чтобы просто писать на js, часть логики будет на java(gwt), а часть на js

В случае с GWT (может, даже не с GWT, а со сферическим транспайлером Java -> JS в вакууме) писать JS-код нужно сравнительно редко. Даже в GWT, где всё плохо и действительно приходится частенько заводить JSNI, писать кода на JS приходится очень и очень мало. В моём проекте на GWT из 100 тысяч строк на Java на JS было написано о силы строк 50.

Зачем? Почему не взять html+js и не написать нормальный фронтенд без свистоплясок и трансформаций?

Какие конкретно свистопляски? Я таковых не обнаружил. Конечно, на старте GWT пришлось понастраивать, но это везде так. И Spring, и Hibernate пришлось настраивать, и, о боже, npm, webpack и grunt. Причём, не сказал бы, что с GWT было сильно больше свистоплясок, чем с последними тремя технологиями.


js+html выучить в разы легче, чем ту же java, думаю, js+html выучить легче, чем нормально разобраться в GWT =)

Я отлично знаю и Java, и JavaScript, и много других интересных вещей. Однако, мне проще писать на одном языке, в рамках единой экосистемы. Да, язык — это не просто синтаксис и семантика, это целая экосистема, которую он за собой тянет. И, кстати, их тоже надо изучать, и на это далеко не всегда есть время и силы.

Information

Rating
Does not participate
Location
München, Bayern, Германия
Date of birth
Registered
Activity

Specialization

Specialist
Senior
From 6,000 €
Java
Compilers
Kotlin
Gradle