Como os compiladores sabem sobre outras classes e suas propriedades?

14

Estou escrevendo minha primeira linguagem de programação orientada a objetos e até agora muito boa em criar uma única 'classe'. Mas, digamos que eu queira ter aulas, digamos ClassAe ClassB. Desde que esses dois não tenham nada a ver um com o outro, tudo ficará bem. No entanto, digamos que ClassAcrie um ClassB- isto coloca duas questões relacionadas:

-Como o compilador saberia ao compilar ClassAque ClassBexiste e, se existir, como saberá suas propriedades?

Até agora, meus pensamentos foram: em vez de compilar cada classe de cada vez (ou seja, digitalizar, analisar e gerar código) cada arquivo "(não realmente arquivo, por si só, mas uma" classe "), preciso digitalizar + analisar cada primeiro , em seguida, gerar código para todos?

OnResolve
fonte

Respostas:

13

Diferentes idiomas (e, portanto, compiladores) abordam isso de maneira diferente.

Na família C, os diferentes módulos têm um arquivo de cabeçalho correspondente que é usado ao criar o objeto. Os arquivos de cabeçalho fornecem informações sobre o tamanho do objeto e quais funções ou métodos existem que podem ser chamados. Isso permite as informações necessárias para alocação de memória e "esse método / função / procedimento existe?" isso é usado ao fazer a compilação de uma única unidade que não precisa ter acesso à própria fonte.

Em Java, o compilador está ciente das coisas em seu caminho de classe e inspeciona o objeto vinculado a eles (verificando se os métodos existem, se possui o número certo de argumentos, etc ...). O Java também pode vincular dinamicamente no carregamento do tempo de execução em outras classes que não sabe nada sobre quando foi compilado. Consulte Class.forName para obter um exemplo de carregamento dinâmico.

Ambas as opções são bastante válidas e têm seu próprio conjunto de vantagens e desvantagens. Fornecer arquivos de cabeçalho que alguns consideram DRY pesado e violador . Por outro lado, se você não possui arquivos de cabeçalho, as bibliotecas precisam ser inspecionáveis ​​pelo compilador e pelo vinculador - um .so ou .dll provavelmente não terá informações suficientes para instanciar adequadamente os objetos ou validar as chamadas de método ( e seria dependente da máquina).

Comunidade
fonte
0

Na prática, com Java, o IDE analisa um programa inteiro de uma só vez; quando a classe B é referenciada, o compilador IDE examinará. Tudo, incluindo as bibliotecas, é um todo completo. Quando o programa estiver pronto, você poderá alterar os caminhos da classe, trocar e excluir arquivos .class individuais e alternar as versões da biblioteca. Você também pode compilar arquivos .java individuais sem usar o IDE (ou de alguma forma evitar verificações). O resultado não precisa ser consistente em todos, e se não é você vai obter exceções de tempo de execução. (Uma das muitas coisas que um IDE está tentando fazer por você é transformar erros de tempo de execução em erros de tempo de compilação, ou melhor, de tempo de edição).

O C # é o mesmo, e não acho que C e C ++ sejam realmente tão diferentes, pois o que os Java e C # IDE estão fazendo é apenas criar cabeçalhos no estilo C / C ++ para você nos bastidores.

RalphChapin
fonte
Os compiladores Java também compilam itens dependentes, se necessário. Você só recebe exceções de tempo de execução desse tipo de coisa se realmente tentou forçar as coisas (por exemplo, alterar e recompilar uma API depois de compilar os consumidores dessa API).
Donal Fellows
@DonalFellows: Meus problemas estão faltando bibliotecas ("Mas eu coloquei essa em todas as minhas máquinas!") E recompilei os programas em execução (arquivos .class de troca não intencional). Posso prever a atualização de pacotes que não correspondem mais ao programa principal, embora ainda não o tenha feito. Eu fiz muito disso com C e .dll (e ele fez comigo) anos atrás. Acredito e espero que haja muitas proteções em vigor agora que não existiam na época.
RalphChapin
Realmente não entendo o que um IDE tem a ver com como um compilador / vinculador sabe como resolver problemas de compilador / vinculador. Corrija-me se estiver errado, mas um IDE é totalmente ortogonal a todo o problema (exceto que facilita a tarefa no programador). Por quê? Porque, em teoria, o IDE usa o compilador em segundo plano.
Thomas Eding 24/03
@ Thomashoding: Você está certo. Quando respondi a essa pergunta, parecia estar tendo problemas para separar o IDE do compilador / vinculador. Minha desculpa: Java não "vincula" até que seja executado e, portanto, não pode saber que uma referência de classe ou chamada de método está errada até então; o IDE realmente não "facilita" minha tarefa, torna possível. Eu costumava (no FORTRAN e C, há muito tempo) obter erros quando compilei, vinculei e executei. Agora, quase todos esses erros são corrigidos quando os digito, o que torna o IDE um compilador, vinculador e executor, em certo sentido. Hoje, todos os erros fora do tempo de execução vêm do IDE.
RalphChapin
0

Os idiomas mais antigos às vezes são mais rigorosos; considere o que é possível em Java:

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

public class Implem implements Ifc {
}

Eu já vi o antipadrão acima, e é realmente feio (eu o teria proibido). Ambas as unidades de compilação se usam. Mas o Ifc pode ser compilado para codificar sem ter um implemento compilado. O código compilado, .class, comparável a um C .obj, contém "informações de ligação:" uma importação do Implem, chamando um construtor sem parâmetros Implem(). A classe Implem pode então ser compilada sem problemas. Em parte, o ClassLoader - executando os dados da classe JVM de inicialização / construção e, em parte, a própria Java Virtual Machine, desempenham um pouco como vinculador , integrando todos.

Por exemplo, compilar com uma versão de uma biblioteca específica e executar com outra versão dessa biblioteca reconhecerá erros de tempo de execução.

Portanto, a resposta: A compilação fornece unidades de código de objeto compilado, que é necessário ver como código + dados + API para vinculação.

Posteriormente, o compilador também deve fazer uma compactação e verificar a API de ligação; uma segunda fase.

Isso pode irritar e parecer deselegante, mas as provas matemáticas podem operar da mesma maneira: ao provar toda a exatidão, já é possível considerar uma parte como verdadeira até a verificação.

Joop Eggen
fonte