Як компілятори знають про інші класи та їх властивості?


14

Я пишу свою першу мову програмування, орієнтовану на об'єкти і поки що хороша, щоб створити єдиний 'клас'. Але, скажімо, я хочу мати заняття, скажімо, ClassAі ClassB. За умови, що ці двоє не мають нічого спільного один з одним, тоді все добре. Однак, скажімо, ClassAстворює - ClassBце ставить 2 пов'язані питання:

-Як би знав компілятор при компіляції, ClassAщо він ClassBнавіть існує, і якщо він є, як він знає, що це властивості?

Досі мої думки були: замість того, щоб компілювати кожен клас одночасно (тобто сканувати, аналізувати та генерувати код) кожен "файл (не справді файл, як такий, але" клас "), чи потрібно мені сканувати + аналізувати кожен перший , а потім генерувати код для всіх?

Відповіді:


13

Різні мови (а отже, і компілятори) підходять до цього по-різному.

У сімействі C різні модулі мають відповідний файл заголовка, який використовується під час створення об'єкта. Файли заголовків надають інформацію про розмір об'єкта та які функції чи методи існують, до яких можна викликати. Це дозволяє отримати необхідну інформацію для розподілу пам'яті і "чи існує цей метод / функція / процедура?" що використовується під час компіляції одного блоку, який не потребує доступу до самого джерела.

У Java компілятор знає про речі на своєму classpath і перевіряє ці об'єкти для зв'язку з ними (перевіряючи, чи існують методи, має правильну кількість аргументів тощо). Java може також динамічно пов'язуватись під час завантаження в інших класах, про що вона нічого не знає, коли вона була складена. Дивіться Class.forName для одного прикладу динамічного завантаження.

Обидва варіанти цілком справедливі і мають свій набір переваг і недоліків. Надання файлів заголовків деякі вважають громіздкими і порушують DRY . З іншого боку, якщо у вас немає файлів заголовків, бібліотеки повинні бути перевірені компілятором і лінкером - .so або .dll, ймовірно, не матиме в ньому достатньо інформації, щоб правильно інстанціювати об'єкти або перевірити виклики методу ( і буде залежати від машини).


0

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

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


Java-компілятори також компілюють залежні речі, якщо це необхідно. Виключення з цього виду отримуєте лише в тому випадку, якщо ви дійсно дуже намагалися примусити їх (наприклад, змінити і перекомпілювати API після компіляції споживачів цього API).
Дональні стипендіати

@DonalFellows: У моїх проблемах відсутні бібліотеки ("але я поклав цю на всі мої машини!") Та перекомпіляція запущених програм (ненавмисне гаряча заміна файлів .class). Я можу передбачити оновлення пакетів, які більше не відповідають основній програмі, хоча я цього ще не зробив. Я багато чого робив із C та .dll (і це мені зробили) років тому. Я вірю і сподіваюсь, що зараз існує багато захистів, яких тоді не було.
РальфЧапін

Я дійсно не розумію, що IDE стосується того, як компілятор / лінкер знає, як вирішити проблеми компіляції / зв’язку. Виправте мене, якщо я помиляюся, але IDE є абсолютно ортогональним для всього питання (за винятком того, що це полегшує завдання програмісту). Чому? Тому що теоретично IDE використовує компілятор у фоновому режимі.
Томас Едінг

@ThomasEding: Ви абсолютно праві. Коли я відповів на це запитання, мені здалося, що виникли проблеми з відокремленням IDE від компілятора / лінкера. Моє виправдання: Java не "посилається", поки вона не запущена, і тому не можу знати, що довідник класу або виклик методу до цього часу невірний; IDE не дуже «полегшує» моє завдання, це робить можливим. Я використовував (у FORTRAN і C, давно давно), щоб помилятися, коли я компілював, коли я зв’язував, а потім, коли бігав. Тепер я отримую майже всі ці помилки під час їх введення, що робить IDE компілятором, лінкером та виконавцем у певному сенсі. Сьогодні всі помилки не запущеного часу походять від IDE.
РальфЧапін

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; друга фаза.

Це може роздратувати і виглядати неелегантно, але математичні докази можуть діяти так само: у доведенні всієї правильності можна вже вважати частину, яка є правдою до перевірки.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.