Действительно тонкий вопрос ...
Раньше считалось, что «интерпретируемые» языки были проанализированы и преобразованы в промежуточную форму, которая выполнялась быстрее, но «машина», выполняющая их, была довольно специфичной для языка программой. Вместо этого «скомпилированные» языки были переведены в инструкции машинного кода, поддерживаемые компьютером, на котором они выполнялись. Раннее различие было очень основным - статический и динамический объем. В статически типизированном языке ссылка на переменную может быть в значительной степени разрешена по адресу памяти в нескольких машинных инструкциях - вы точно знали, где в вызывающем кадре указана переменная. В динамически типизированных языках вы должны были искать (вверх по списку А или по вызывающему кадру) ссылку. С появлением объектно-ориентированного программирования не непосредственный характер ссылки расширился до многих других понятий - классов (типов), методов (функций), даже синтаксической интерпретации (встроенных DSL, таких как regex).
Различие, по сути, восходящее к концу 70-х годов, было не столько между скомпилированными и интерпретируемыми языками , сколько в том, были ли они запущены в скомпилированной или интерпретированной среде.
Например, Паскаль (первый язык высокого уровня, который я изучил) работал в Калифорнийском университете в Беркли сначала на интерпретаторе Билла Джоя pxp , а затем на компиляторе он написал pcc . Один и тот же язык, доступный как в скомпилированной, так и в интерпретируемой среде.
Некоторые языки более динамичны, чем другие, значение чего-либо - типа, метода, переменной - зависит от среды выполнения. Это означает, что скомпилированный или нет существенный механизм времени выполнения, связанный с выполнением программы. Forth, Smalltalk, NeWs, Lisp, все были примерами этого. Первоначально эти языки требовали так много механизмов для выполнения (по сравнению с C или Fortran), что они были естественными для интерпретации.
Еще до Java были попытки ускорить выполнение сложных динамических языков с помощью хитростей, техник, которые превратились в многопоточную компиляцию, компиляцию точно в срок и т. Д.
Я думаю, что это была Java, которая была первым широко распространенным языком, который действительно запятнал пробел в компиляторе / интерпретаторе, по иронии судьбы не так, чтобы он работал быстрее (хотя и это тоже), но так, чтобы он работал везде. Определив свой собственный машинный язык и «машинный» байт-код java и виртуальную машину, Java попыталась стать языком, скомпилированным во что-то близкое к любой базовой машине, но не к реальной машине.
Современные языки объединяют все эти инновации. Некоторые имеют динамическую открытую природу традиционных интерпретируемых языков типа «ты не знаешь, что получишь до времени выполнения» (ruby, lisp, smalltalk, python, perl (!)), Некоторые пытаются иметь строгую спецификацию, позволяющую детально обнаруживать статические ошибки на основе типов в традиционных скомпилированных языках (java, scala). Все компилируются в фактические машинно-независимые представления (JVM), чтобы получить семантику однократной записи в любом месте.
Итак, скомпилировано или интерпретировано? Лучше всего, я бы сказал. Весь код находится в источнике (с документацией), что-то меняется, и эффект мгновенный, простые операции выполняются почти так же быстро, как аппаратное обеспечение, сложные, поддерживаются и достаточно быстрые, модели оборудования и памяти согласованы на разных платформах.
Большая полемика в современных языках, вероятно, заключается в том, являются ли они статически или динамически типизированными, то есть не в том, насколько быстро они будут работать, но будут ли ошибки заранее обнаруживаться компилятором (за счет того, что программисту приходится указывать довольно сложная информация) или ошибки будут появляться при тестировании и производстве.