Как компиляторы знают о других классах и их свойствах?

14

Я пишу свой первый язык программирования, который является объектно-ориентированным и до сих пор хорош в создании единого «класса». Но, скажем, я хочу, чтобы уроки, скажем, ClassAи ClassB. Если эти двое не имеют ничего общего друг с другом, тогда все хорошо. Однако, скажем, ClassAсоздает - это ClassBставит 2 связанных вопроса:

-Как узнать компилятор при компиляции, ClassAкоторый ClassBдаже существует, и, если он это делает, как он узнает о его свойствах?

До сих пор я думал: вместо того, чтобы компилировать каждый класс за раз (т. Е. Сканировать, анализировать и генерировать код), каждый «файл (на самом деле не файл, как таковой, а« класс ») мне нужно сначала сканировать + анализировать каждый» , а потом сгенерировать код для всех?

OnResolve
источник

Ответы:

13

Разные языки (и, следовательно, компиляторы) подходят к этому по-разному.

В семействе C разные модули имеют соответствующий заголовочный файл, который используется при создании объекта. Заголовочные файлы предоставляют информацию о размере объекта и о том, какие функции или методы существуют, которые могут быть вызваны. Это позволяет получить необходимую информацию для выделения памяти и «существует ли этот метод / функция / процедура?» это используется при выполнении компиляции одного модуля, которому не нужен доступ к самому источнику.

В Java компилятор знает о вещах в своем пути к классам и проверяет, чтобы эти объекты связывались с ними (проверяя, что методы существуют, имеют правильное количество аргументов и т. Д.). Java также может динамически связываться при загрузке во время выполнения в других классах, о которых она ничего не знает, когда была скомпилирована. См. Class.forName для одного примера динамической загрузки.

Оба варианта вполне допустимы и имеют свой набор преимуществ и недостатков. Предоставление заголовочных файлов некоторые считают громоздкими и нарушающими DRY . С другой стороны, если у вас нет заголовочных файлов, библиотеки должны проверяться компилятором и компоновщиком - вероятно, в .so или .dll не будет достаточно информации для правильной реализации объектов или проверки вызовов методов ( и будет зависеть от машины).

Сообщество
источник
0

Практически, с Java, среда IDE смотрит на всю программу одновременно; когда ссылка на ClassB, компилятор IDE будет смотреть на это. Все, включая библиотеки, является одним целым. Когда программа будет готова, вы можете изменить пути к классам, поменять местами отдельные файлы .class и переключать версии библиотек. Вы также можете скомпилировать отдельные файлы .java без использования IDE (или как-то избежать проверки). Результат не должен быть последовательным на всех, и если это не вы будете получать во время выполнения исключения. (Одна из многих вещей, которые IDE пытается сделать для вас, - это превращать ошибки времени выполнения в ошибки времени компиляции или, точнее, ошибки времени редактирования.)

C # примерно одинаковы, и я не думаю, что C и C ++ действительно отличаются друг от друга тем, что Java и C # IDE просто создают заголовки в стиле C / C ++ для вас за кулисами.

RalphChapin
источник
Java-компиляторы также компилируют зависимые вещи, если это необходимо. Вы получаете исключения времени выполнения от такого рода вещей, если вы действительно очень сильно пытались форсировать вещи (например, изменить и перекомпилировать API после компиляции потребителей этого API).
Донал Феллоуз
@DonalFellows: У меня проблемы с отсутствием библиотек («Но я поставил его на все мои машины!») И перекомпиляцией запущенных программ (непреднамеренно горячей замены файлов .class). Я могу предвидеть обновление пакетов, которые больше не соответствуют основной программе, хотя я еще этого не сделал. Я делал это с C и .dll (и сделал это со мной) много лет назад. Я верю и надеюсь, что сейчас существует множество защитных мер, которых тогда не было.
RalphChapin
Я действительно не понимаю, что IDE имеет отношение к тому, как компилятор / компоновщик знает, как решать проблемы компиляции / компоновщика. Поправьте меня, если я ошибаюсь, но IDE полностью ортогональна ко всей проблеме (за исключением того, что она облегчает задачу программиста). Почему? Потому что в теории IDE использует компилятор в фоновом режиме.
Томас Эдинг
@ThomasEding: Вы совершенно правы. Когда я ответил на этот вопрос, у меня возникли проблемы с отделением IDE от компилятора / компоновщика. Мое оправдание: Java не "связывается" до тех пор, пока не запустится, и поэтому не может знать, что ссылка на класс или вызов метода неверны до тех пор; IDE на самом деле не «облегчает» мою задачу, она делает это возможным. Я использовал (в FORTRAN и C, очень давно), чтобы получать ошибки при компиляции, когда я связывался, а затем, когда я запускался. Теперь я почти все эти ошибки исправляю по мере их ввода, что в некотором смысле делает IDE компилятором, компоновщиком и исполнителем. Сегодня все ошибки не во время выполнения происходят из IDE.
RalphChapin
0

Старые языки иногда более строгие; рассмотрим, что возможно в Java:

public interface Ifc {
    public static final Ifc MY_CONSTANT = new Implem();
}

public class Implem implements Ifc {
}

Я видел анти-шаблон выше, и он действительно ужасен (я бы запретил его). Оба модуля компиляции используют друг друга. Но Ifc можно скомпилировать в код без скомпилированного Implem. Скомпилированный код .class, сравнимый с C .obj, содержит «информацию о связях»: импорт Implem, вызывающий конструктор без параметров Implem(). Класс Implem может быть скомпилирован без проблем. Частично ClassLoader - выполнение данных класса JVM для инициализации / сборки, а частично и сама виртуальная машина Java играют роль компоновщика , объединяя все.

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

Итак, ответ: Компиляция предоставляет единицы скомпилированного объектного кода, которые нужно видеть как код + данные + API для связывания вместе.

Компилятор должен впоследствии также сделать упаковку вместе, и проверить на подъёмник API; второй этап.

Это может раздражать и выглядеть не элегантно, но математические доказательства могут действовать таким же образом: при доказательстве полной правильности можно уже считать, что часть остается верной до проверки.

Joop Eggen
источник