Pull to refresh

Comments 15

Не деревья абстрактного синтаксиса, а абстрактное синтаксическое дерево
издержки дословного перевода

Тогда уж не «лексинг» и не «токенизация», а «лексический разбор». Не «токены», а «лексемы». «Парсинг» — тоже жаргонизм для «синтаксического разбора», хотя он более-менее устоялся.

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

С перепугу, конечно, можно сделать такую программу, что будет час компилироваться. Но кто в здравом уме будет держать проект в десятки-сотни тысяч строк в одном файле? Проект будет разбит на мелкие логические куски и при минимальных усилиях, потраченных на дизайн, перекомпилирован будет только измененный кусок. А это — секунды. В крайнем случае, десятки секунд.

Я согласен считать слова про почти час риторическим приемом, но тогда было бы уместно как-то более явно это указать.
Если вы исправили какой-нибудь .h файл нижнего уровня в большом сишном проекте (например, включающий определения базовых типов), то перекомпилироваться будет всё и долго. Хотя это недостаток конкретно языка Си с его повсеместными иерархическими макроподстановками, а не вообще компилируемых языков.
Два соображения. Насколько часто вы правите заголовочник с определениями базовых типов? И поосторожнее с кванторами всеобщности.

P.S. а что вы имеет в виду под «Си с его повсеместными иерархическими макроподстановками»? И как это связано с определениями типов?
Си устроен так, что компилятор не знает ни о каких изменениях типов, а просто текстуально подставляет макровставки из заголовочных файлов по #include. Поэтому изменение заголовочного файла влечёт повторную компиляцию всех исходных модулей, в которых он используется, причём даже независимо от того, в каком именно месте он был изменён, и используется ли в этих модулях изменённое место.

Про “часто” никто не писал. В цитате, которую Вы комментируете, написано “могут”.
си не знает… простите, а какой язык — знает? что вы, собственно, имеете в виду, говоря «компилятор не знает об изменении типов»?

вы путаете макроподстановки и определения типов. макроподстановки — это не си, а препроцессор. а перекомиляция всех исходных модулей из-за изменения в одном заголовчнике — это, как я выше говорил, вопрос дизайна.

если не «часто», а могут без всяких численных оценок, то это довольно бессмысленное утверждение. если я один раз на 1000 перекомпиляций буду вынужден ждать десять минут вместо десяти секунд это не затормозит процесс разработки сколько-нибудь заметно.
Препроцессор является частью языка Си. А в языке Си нет другого способа экспортировать определение типа в другой модуль, кроме как включить в него текст этого определения через препроцессор.

В языках, реализующих управление модулями (Ада, Модула, Delphi) эта проблема перекомпиляции носит более ограниченный характер, так как перекомпилируются только модули, непосредственно включающие изменённый модуль или включающие зависящие от него интерфейсы. А в языках с динамической типизацией, вроде Smalltalk, вообще изменение типа используемого объекта – не повод что-либо перекомпилировать, кроме его собственной реализации.
Кстати, JIT в некоторых случаях может быть быстрее, чем компилированный в native вариант. Это случай, когда компилятор еще не знает про целевую архитектуру (и, соотвественно, генерирует подоптимальный код), а JIT уже знает и поэтому может — теоретически — сгенерировать код оптимальный для целевой архитектуры.

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

Я в курсе. Но это с другой стороны взгляд, если хотите. Для того, чтобы получить выигрыш от знания целевой архитектуры по сравнению с компилятором JIT'y необязательно быть умным — достаточно знать целевую архитектуру.

Впрочем, в реальной жизни выигрыш (если он возникает) будет более вероятно за счет умной профилировки по данным. Надо бы JVM'щиков спросить…
Интересная статья. Всё наглядно и подробно объясняется. Мне понравилось. Спасибо.
Спасибо за статью, очень хорошо изложили тему.
Закрыл для себя кусок знаний, о котором давно хотел почитать.
Sign up to leave a comment.