Почему почти все языки OO компилируются в байт-код? - PullRequest
17 голосов
/ 18 октября 2010

Из известных мне объектно-ориентированных языков почти все, кроме C ++ и Objective-C, компилируются в байт-код, работающий на какой-то виртуальной машине.Почему так много разных языков остановилось на компиляции в байт-код, в отличие от машинного кода?Возможно ли в princible иметь высокоуровневый язык ООП, управляемый памятью, который скомпилирован в машинный код?

Редактировать: Мне известно, что поддержка мультиплатформенности часто продвигается как преимущество этого подхода.Тем не менее, вполне возможно изначально компилировать на нескольких платформах, без создания нового компилятора для каждой платформы.Например, можно сгенерировать код на C, а затем скомпилировать его с помощью GCC.

Ответы [ 8 ]

13 голосов
/ 18 октября 2010

На самом деле нет причин, это своего рода совпадение. ООП в настоящее время является ведущей концепцией в "большом" программировании, и виртуальные машины тоже.

Также обратите внимание, что есть 2 отдельные части традиционных виртуальных машин - сборщик мусора и интерпретатор байт-кода / JIT-компилятор , и эти части могут существовать отдельно. Например, реализация Common Lisp, называемая SBCL, компилирует программу в собственный код, но во время выполнения интенсивно использует сборку мусора.

12 голосов
/ 18 октября 2010

Это сделано для того, чтобы компилятор ВМ или JIT мог оптимально компилировать код по требованию для архитектуры, на которой выполняется код. Кроме того, он позволяет создавать кроссплатформенный байт-код один раз, а затем выполнять его на нескольких аппаратных архитектурах. Это позволяет размещать определенные аппаратные оптимизации в скомпилированном коде.

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

Тогда есть проблема безопасности. Байт-код может быть проверен и проанализирован перед выполнением (т. Е. Переполнения буфера нет, переменные определенного типа обращаются как к чему-то, что они не имеют) и т. Д.

4 голосов
/ 18 октября 2010

Java использует байт-код, потому что двумя его первоначальными целями разработки были мобильность и компактность. Оба они исходили из первоначального видения языка для встроенных устройств, где фрагменты кода можно было загружать на лету.

Python, Ruby, Smalltalk, javascript, awk и т. Д. Используют байт-код, потому что написание нативного компилятора - большая работа, но текстовый интерпретатор слишком медленный - байт-код поражает приятное место, поскольку его довольно легко написать, но также достаточно быстро бегать.

Я понятия не имею, почему языки Microsoft используют байт-код, поскольку для них ни портативность, ни компактность не имеют большого значения. Большая часть размышлений о CLR исходила от компьютерных ученых в Кембридже, поэтому я думаю, что были приняты во внимание такие соображения, как простота анализа и проверки программ.

Обратите внимание, что наряду с C ++ и Objective C, Eiffel, Ada 9X, Vala и Go являются ОО-языками (различного происхождения), которые скомпилированы прямо в нативный код.

В целом, я бы сказал, что ОО и байт-код не идут рука об руку. Скорее, мы имеем совпадение нескольких потоков разработки: традиционные интерпретаторы байт-кодов языков сценариев, таких как Python и Ruby, безумный мастер-план Гослинга Java, и каковы бы ни были мотивы Microsoft.

3 голосов
/ 18 октября 2010

Самая большая причина, по которой большинство интерпретируемых языков (не только ОО-языков) скомпилированы в байт-код, связана с производительностью. Самая дорогая часть интерпретации кода - это преобразование исходного текста в промежуточное представление. Например, выполнить что-то вроде:

foo + bar;

Интерпретатор должен отсканировать 10 символов, преобразовать их в 4 токена, построить AST для операции, разрешить три символа (+ - это символ, который зависит от типов foo и bar), и все это перед тем, как он сможет выполнить любое действие, которое на самом деле зависит от состояния программы во время выполнения. Ничто из этого не может измениться от запуска к запуску, и поэтому многие языки пытаются сохранить некоторую форму промежуточного представления.

байт-код, а не хранение AST имеет несколько преимуществ. С одной стороны, байт-коды легко сериализуются, поэтому IR можно записать на диск и использовать повторно при следующем вызове, что еще больше сокращает время интерпретации. Другая причина в том, что байт-код часто занимает меньше фактической памяти. в значительной степени представления байт-кода часто легко компилировать вовремя, потому что они часто структурно похожи на типичный машинный код.

1 голос
/ 18 октября 2010

В качестве еще одной точки данных, язык программирования D является GC'ом, OO и имеет намного более высокий уровень, чем C ++, хотя все еще компилируется в собственный код.

1 голос
/ 18 октября 2010

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

Байт-код, как правило, также более оптимизирован, чем интерпретатор, потому что он ближе к машинным инструкциям и поэтому быстрее переводится на машинные инструкции.Не все ОО языки скомпилированы.Ruby, Python и даже Javascript интерпретируются так, что они не скомпилированы ни с чем, поэтому интерпретатор ruby ​​должен использовать очень гибкий язык и превращать его в инструкции, но эта гибкость достигается ценой, заплаченной за время выполнения: анализировать текст, генерировать AST, переводить AST в машинный код и т. д. Также легко выполнять оптимизацию, например JIT, где байт-код транслируется непосредственно в машинный код, и даже дает возможность создавать оптимизации для конкретного оборудования.

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

ОО и компиляция байт-кода восходит к 70-м годам с Smalltalk, и я уверен, что кто-то скажет LISP еще в 50-х / 60-х годах.,Но только в 90-х годах он начал широко использоваться в производственных системах в больших масштабах.

Собственная компиляция звучит как оптимальный путь, и, вероятно, почему наша отрасль провела 20 или более лет, размышляяэто было ответом на все наши проблемы, но за последние 15 лет мы увидели, что компиляция байт-кода вступила в стадию, и это было значительным преимуществом по сравнению с тем, что мы делали раньше.Оглядываясь назад, мы понимаем, сколько времени было потрачено на компиляцию всего вручную.

0 голосов
/ 18 октября 2010

Разработать интерпретатор проще, чем компилятор.

Усилие при разработке ...:

интерпретатор <байт-код-интерпретатор <байт-код-jit-компилятор <компилятор дляплатформа-независимый язык <компилятор-несколько-машин-зависимый ассемблер. </p>

Это общая тенденция - останавливать разработку на jit-компиляторах из-за независимости от платформы.Только предпочтительные языки в отношении производительности и исследований в области теоретической информатики существуют и будут развиваться во ВСЕХ возможных направлениях, включая новый интерпретатор байт-кода, даже при том, что существуют хорошие и продвинутые компиляторы для независимых от платформы языков и для различных машинно-зависимых ассемблеров.

Исследования на языках ООП довольно приятны ... скажем, скучно по сравнению с функциональными языками, потому что действительно новые языковые и компиляторные технологии легче выразить с помощью / в / с использованием математической теории категорий и математических описаний туров.полные системы типов.Другими словами: он почти функциональный сам по себе, в то время как императивные языки являются почти только интерфейсом ассемблера с некоторым синтаксическим сахаром.ООП языки, как правило, являются императивными языками, потому что функциональные языки уже имеют замыкания и лямбду.Существуют и другие способы реализации java-подобных «интерфейсов» в функциональных языках, и нет необходимости в дополнительных объектно-ориентированных функциях.

В ie Haskell добавление возможности OOP-подобного программирования, вероятно, было бы болеечем только несколько шагов назад в технологии - не было бы смысла использовать это.(<- это не только ИМХО ... вы когда-нибудь слышали о GADT или классах с несколькими параметрами?) Возможно, могут быть даже лучшие способы динамического создания объектов с интерфейсами для взаимодействия с ООП-языками, чем изменение самого этого языка,Но есть и другие функциональные языки, которые явно объединяют функциональные аспекты и ООП.Просто больше науки с преимущественно функциональными языками, чем с нефункциональными OO-языками. </p>

Языки OO не могут быть легко скомпилированы с другими языками OO, если они в некотором роде более "продвинуты".Обычно они имеют такие функции, как защита стека, расширенные возможности отладки, абстрактная и проверяемая многопоточность, динамическая загрузка объектов из файлов из Интернета ... Многие из этих функций трудно или не так просто реализовать с помощью C или C ++ в качестве компилятора.-backend.Функциональный язык LISP (которому 50 лет!) Был AFAIK первым с сборщиком мусора.В качестве бэкэнда компилятора LISP использовал взломанную версию языка C, потому что обычный C не разрешал некоторые из этих вещей, а ассемблер разрешал, т.е.C-- допускает это.

Другой аспект: императивные языки предназначены для работы на определенной архитектуре, то есть программы на C и C ++ работают только на тех архитектурах, для которых они запрограммированы.Java более экстремален: он работает только на одной архитектуре, виртуальной, которая сама работает на других.Функциональные языки обычно по своему дизайну довольно независимы от архитектуры: LISP был разработан так, чтобы быть настолько не зависящим от архитектуры, что его можно было бы скомпилировать в генетический код в некотором отдаленном будущем.Да, как программы, работающие в живых биологических ячейках.

С помощью байт-кода для LLVM функциональные языки, скорее всего, будут скомпилированы в байт-код и в будущем.Большинство императивных языков, скорее всего, все еще будут иметь те же унаследованные проблемы, что и сейчас, когда они недостаточно абстрагированы.Ну, я не совсем уверен насчет Clang и D, но эти двое в любом случае не "самые".

0 голосов
/ 18 октября 2010

Я согласен с ответом Чуббарда и добавлю, что в языках ОО информация о типах может быть очень важна для обеспечения оптимизации на виртуальных машинах или компиляторах последнего уровня

...