Comment les compilateurs connaissent-ils les autres classes et leurs propriétés?


14

J'écris mon premier langage de programmation orienté objet et jusqu'ici tout va bien avec la création d'une seule «classe». Mais, disons que je veux avoir des cours, disons ClassAet ClassB. À condition que ces deux-là n'aient rien à voir l'un avec l'autre, alors tout va bien. Cependant, disons ClassAcrée un ClassB- ce qui pose 2 questions liées:

-Comment le compilateur saurait-il lors de la compilation ClassAque ClassBcela existe, et, si c'est le cas, comment sait-il que ce sont ses propriétés?

Jusqu'à présent, je pensais: au lieu de compiler chaque classe à la fois (c'est-à-dire scanner, analyser et générer du code) chaque "fichier (pas vraiment un fichier en soi, mais une" classe ") dois-je scanner + analyser chaque premier , puis générer du code pour tous?

Réponses:


13

Différentes langues (et donc des compilateurs) abordent cela différemment.

Dans la famille C, les différents modules ont un fichier d'en-tête correspondant qui est utilisé lors de la construction de l'objet. Les fichiers d'en-tête fournissent des informations sur la taille de l'objet et les fonctions ou méthodes qui peuvent être invoquées. Cela permet d'obtenir les informations nécessaires pour l'allocation de mémoire et "existe-t-il cette méthode / fonction / procédure?" qui est utilisé lors de la compilation d'une seule unité qui n'a pas besoin d'avoir accès à la source elle-même.

En Java, le compilateur est au courant des choses sur son chemin de classe et inspecte ces objets pour les lier (vérifier que les méthodes existent, avoir le bon nombre d'arguments, etc ...). Java peut également se lier dynamiquement au chargement de l'exécution dans d'autres classes dont il ne sait rien au moment de sa compilation. Voir Class.forName pour un exemple de chargement dynamique.

Les deux options sont tout à fait valables et ont leur propre ensemble d'avantages et d'inconvénients. Fournir des fichiers d'en-tête que certains considèrent comme lourds et violant DRY . D'un autre côté, si vous n'avez pas de bibliothèques de fichiers d'en-tête, elles doivent être inspectables par le compilateur et l'éditeur de liens - un fichier .so ou .dll ne contiendra probablement pas suffisamment d'informations pour instancier correctement les objets ou valider les appels de méthode ( et dépendrait de la machine).


0

Concrètement, avec Java, l'IDE regarde d'un seul coup un programme entier; lorsque ClassB est référencé, le compilateur IDE l'examine. Tout, y compris les bibliothèques, est un tout complet. Une fois que le programme est prêt, vous pouvez modifier les chemins de classe, permuter et échanger des fichiers .class individuels et changer de version de bibliothèque. Vous pouvez également compiler des fichiers .java individuels sans utiliser l'EDI (ou éviter en quelque sorte ses vérifications). Le résultat n'a pas besoin d'être cohérent du tout, et si ce n'est pas vous sera pour la course à temps exceptions. (L'une des nombreuses choses qu'un IDE essaie de faire pour vous est de transformer les erreurs d'exécution en erreurs de compilation, ou plutôt de modification).

Les C # sont à peu près les mêmes, et je ne pense pas que C et C ++ soient vraiment si différents, en ce que les IDE Java et C # font simplement créer des en-têtes de style C / C ++ pour vous dans les coulisses.


Les compilateurs Java compilent également des éléments dépendants, si nécessaire. Vous n'obtenez des exceptions d'exécution de ce genre de chose que si vous avez vraiment essayé de forcer les choses (par exemple, changer et recompiler une API après avoir compilé les consommateurs de cette API).
Donal Fellows

@DonalFellows: Mes problèmes ont manqué des bibliothèques ("Mais j'ai mis celle-là sur toutes mes machines!") Et recompilé les programmes en cours d'exécution (fichiers .class involontairement remplaçables à chaud). Je peux prévoir la mise à jour de packages qui ne correspondent plus au programme principal, même si je ne l'ai pas encore fait. J'ai fait beaucoup de cela avec C et .dll (et je l'ai fait) il y a des années. Je crois et j'espère qu'il y a beaucoup de protections en place maintenant qui n'existaient pas à l'époque.
RalphChapin

Je ne comprends vraiment pas ce qu'un IDE a à voir avec la façon dont un compilateur / éditeur de liens sait comment résoudre les problèmes de compilation / éditeur de liens. Corrigez-moi si je me trompe, mais un IDE est totalement orthogonal à l'ensemble du problème (sauf qu'il facilite la tâche du programmeur). Pourquoi? Parce qu'en théorie, l'EDI utilise le compilateur en arrière-plan.
Thomas Eding

@ThomasEding: Vous avez tout à fait raison. Lorsque j'ai répondu à cette question, je semblais avoir du mal à séparer l'IDE du compilateur / éditeur de liens. Mon excuse: Java ne "lie" pas jusqu'à ce qu'il s'exécute et ne peut donc pas savoir qu'une référence de classe ou un appel de méthode est incorrect jusque-là; l'IDE ne "facilite" pas vraiment ma tâche, il le rend possible. J'ai utilisé (dans FORTRAN et C, il y a très longtemps) pour obtenir des erreurs lors de la compilation, lors de la liaison, puis lors de l'exécution. Maintenant, je reçois presque toutes ces erreurs lorsque je les tape, ce qui fait de l'EDI un compilateur, un éditeur de liens et un exécuteur, dans un sens. Aujourd'hui, toutes les erreurs non liées à l'exécution proviennent de l'EDI.
RalphChapin

0

Les langues plus anciennes sont parfois plus strictes; considérez ce qui est possible en Java:

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

public class Implem implements Ifc {
}

J'ai vu l'anti-pattern ci-dessus, et c'est vraiment moche (je l'aurais interdit). Les deux unités de compilation s’utilisent. Mais Ifc peut être compilé en code sans avoir d'implem compilé. Le code compilé, .class, comparable à un C .obj, contient des "informations de liaison:" une importation d'Implem, appelant un constructeur sans paramètre Implem(). La classe Implem peut ensuite être compilée sans problème. En partie le ClassLoader - faisant l'initialisation / la construction des données de classe JVM, et en partie la machine virtuelle Java elle-même, jouent un peu comme l' éditeur de liens , intégrant tout.

Par exemple, la compilation avec une version d'une bibliothèque spécifique et son exécution avec une autre version de cette bibliothèque reconnaîtront les erreurs d'exécution.

Donc, la réponse: la compilation fournit des unités de code objet compilé, que l'on doit voir comme code + données + API pour les relier ensemble.

Le compilateur doit ensuite également effectuer un regroupement et vérifier l'API de liaison; une deuxième phase.

Cela peut irriter et paraître inélégant, mais les preuves mathématiques peuvent fonctionner de la même manière: en prouvant l'exactitude entière, on peut déjà considérer qu'une partie est vraie jusqu'à la vérification.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.