O que é vinculação antecipada e tardia?
On Novembro 18, 2020 by adminSempre ouço sobre vinculação antecipada e tardia, mas não entendo o que são. Encontrei a seguinte explicação que não entendo:
A vinculação inicial se refere à atribuição de valores a variáveis durante o tempo de design, enquanto a vinculação tardia se refere à atribuição de valores às variáveis durante o tempo de execução.
Alguém poderia definir os dois tipos de vinculação e compará-los?
Comentários
- tempo de compilação vs tempo de execução.
- Aqui está uma boa leitura sobre o assunto: en.wikibooks.org/ wiki / Introduction_to_Programming_Languages / …
Resposta
Existem dois conceitos principais na confusão: encadernação e carregamento. É confundido pelo conceito de DataBinding, que está em algum lugar no meio, geralmente fazendo as duas coisas. Depois de considerar isso, vou adicionar mais um conceito, para completar a trifeta, despacho.
Tipos
Ligação tardia : o tipo é desconhecido até que a variável seja exercida durante o tempo de execução; geralmente por meio de atribuição, mas existem outros meios para coagir um tipo; linguagens tipadas dinamicamente chamam isso de um recurso subjacente, mas muitas linguagens tipadas estaticamente têm algum método de alcançar vinculação tardia
Implementado frequentemente usando tipos dinâmicos [especiais], introspecção / reflexão, sinalizadores e opções de compilador ou por meio de métodos virtuais pegando emprestado e estendendo o despacho dinâmico
Vinculação antecipada : o tipo é conhecido antes que a variável seja exercida durante o tempo de execução, geralmente por meio estático e declarativo
Implementado frequentemente usando tipos primitivos padrão
Funções
Despacho estático : função específica conhecida ou sub-rotina em tempo de compilação; não é ambíguo e corresponde à assinatura
Implementado como funções estáticas; nenhum método pode ter a mesma assinatura
Expedição dinâmica : não é uma função específica ou sub-rotina em tempo de compilação; determinado pelo contexto durante a execução. Existem duas abordagens diferentes para “despacho dinâmico”, distinguidas por quais informações contextuais são usadas para selecionar a implementação de função apropriada.
Em único [ dinâmico ] dispatch , apenas o tipo da instância é usado para determinar a implementação da função apropriada. Em linguagens tipadas estaticamente, o que isso significa na prática é que o tipo de instância decide qual implementação de método é usada independentemente do tipo de referência indicado quando a variável é declarada / atribuída. Como apenas um único tipo – o tipo da instância do objeto – é usado para inferir a implementação apropriada, essa abordagem é chamada de “envio único”.
Há também múltiplo [ dinâmico ] despacho , onde os tipos de parâmetro de entrada também ajudam a determinar qual implementação de função chamar. Porque vários tipos – tanto o tipo da instância quanto o (s) tipo (s) do (s) parâmetro (s) – influenciam com a implementação do método selecionada, essa abordagem é denominada “envio múltiplo”.
Implementada como funções virtuais ou abstratas; outras pistas incluem métodos substituídos, ocultos ou sombreados.
NB: Se a sobrecarga de método envolve ou não o despacho dinâmico é específico da linguagem. Por exemplo, em Java, os métodos sobrecarregados são despachados estaticamente.
Valores
Lazy Loading : estratégia de inicialização do objeto que adia a atribuição de valor até que seja necessário ; permite que um objeto esteja em um estado essencialmente válido, mas sabidamente incompleto, e espera até que os dados sejam necessários antes de carregá-lo; frequentemente considerado útil para carregar grandes conjuntos de dados ou aguardar recursos externos
Implementado frequentemente ao não carregar propositadamente uma coleção ou lista em um objeto de composição durante as chamadas de construtor ou inicialização até que algum chamador descendente peça para ver o conteúdo de essa coleção (por exemplo, get_value_at, get_all_as, etc).As variações incluem o carregamento de metainformações sobre a coleção (como tamanho ou chaves), mas omitindo os dados reais; também fornece um mecanismo para alguns tempos de execução para fornecer aos desenvolvedores um esquema de implementação singleton razoavelmente seguro e eficiente
Carregamento rápido : estratégia de inicialização de objeto que executa imediatamente todas as atribuições de valor a fim de ter todos os dados necessários para serem concluídos antes de se considerar em um estado válido.
Implementado frequentemente por fornecer a objetos compostos todos os seus dados conhecidos o mais rápido possível, como durante uma chamada de construtor ou inicialização
Data Binding : frequentemente envolve a criação de um link ativo ou mapa entre dois fluxos de informações compatíveis de modo que as alterações em um sejam refletidas no outro e vice-versa; para serem compatíveis, eles geralmente precisam ter um tipo de base ou interface comum
Implementado frequentemente como uma tentativa de fornecer sincronização mais limpa e consistente entre diferentes aspectos da aplicação (por exemplo, modelo de visualização para visualização, modelo para controlador etc.) e fala sobre conceitos como origem e destino, endpoints, vincular / desvincular, atualizar e eventos como on_bind, on_property_change, on_explicit, on_out_of_scope
EDITAR NOTA: Última edição principal para fornecer uma descrição de exemplos de como isso ocorre com frequência. Exemplos de código específicos dependem inteiramente da implementação / tempo de execução / plataforma
Comentários
- Essa resposta parece muito específica para linguagens orientadas a objetos.
- @Jack não ‘ não me sinto assim, acho que é um excelente que cobre muitos aspectos.
Resposta
Qualquer coisa decidida pelo compilador durante a compilação pode ser consultada em ANTECIPADO / TEMPO DE COMPILAÇÃO A vinculação e tudo o que for decidido em RUNTIME é chamado de LATE / RUNTIME vinculação.
Por exemplo,
Método Sobrecarga e Método Substituição .
1 ) Em Sobrecarga de método , seu método chama os métodos ar e decidido pelo compilador no sentido de que a função que será chamada é decidida por seu compilador em tempo de compilação. Sendo assim EARLY BINDING .
2) No método Overriding, é decidido em RUNTIME qual método é vai ser chamado. Portanto, é referido como ATRASO BINDING .
Tentei mantê-lo simples e fácil de obter. Espero que isso ajude.
Resposta
Vinculação tardia é quando o comportamento é avaliado em tempo de execução. É necessário quando você realmente deseja determinar como agir com base nas informações que você só tem quando o programa está em execução. O exemplo mais claro em minha opinião é o mecanismo de função virtual, especificamente em C ++.
class A { public: void f() {} virtual void g() {} }; class B : public A { void f() {} virtual void g() {} }; int main() { A* a = new B; a->f(); a->g(); }
Neste exemplo, a->f()
irá realmente chamar void A::f()
, porque é cedo (ou estaticamente ) vinculado, e assim o programa em tempo de execução pensa que é apenas um ponteiro para uma A
variável de tipo, enquanto a->g()
irá realmente chamar void B::g()
, porque o compilador, visto que g()
é virtual, injeta código para procurar o endereço da função correta para chamar no tempo de execução.
Comentários
- ” O tempo de execução “? Você ‘ está falando sobre C ++. C ++ compila diretamente para o código de máquina, não ‘ precisa de um tempo de execução para resolver métodos virtuais.
- @tdammers C ++ realmente precisa de uma biblioteca de tempo de execução, embora não para chamadas virtuais. Se você ler com atenção, ‘ notará que esta resposta diz que o compilador ” injeta código para procurar o endereço da função correta [ …] em runtime “.
- Bem, mas esse código ” para pesquisar o endereço da função correta ” é basicamente apenas uma desreferência de ponteiro de dois estágios independente de tipo seguida por uma chamada de função. Não há ” pensamento ” envolvido; a única razão pela qual funciona de forma confiável é porque o compilador faz a verificação de tipo em tempo de compilação ; em tempo de execução, o código gerado confia no compilador para fazer o dever de casa de verificação de tipo. Se você usar conversões não seguras (por exemplo,Casts de ponteiro no estilo C), você pode legalmente tratar objetos C ++ como objetos da classe errada, mas seus vtables ficarão totalmente bagunçados e o código simplesmente quebrará.
- @tdammers Tentei ficar longe desse tipo de resposta, porque ‘ é um detalhe de implementação de compiladores, o que pode ou não ser verdade para algum compilador esotérico. O que importa é o conceito.
- @tdammers E por ” o tempo de execução ” quero dizer ” o programa em tempo de execução “. Obviamente, C ++ não é ‘ gerenciado. Mas, como você me mostrou, isso pode causar confusão, ‘ estou mudando para o texto completo.
Resposta
se você estiver familiarizado com ponteiros de função, este seria um exemplo. As funções definidas podem ser chamadas de vinculação antecipada. enquanto que se você usar os ponteiros de função, sua vinculação tardia.
int add(int x,int y) { return x+y; } int sub(int x,int y) { return x-y; } int main() { //get user choice int(*fp)(int,int); //if add fp=add; //else if sub fp=sub; cout<<fp(2,2); }
aqui as funções add e sub são funções (seu endereço é vinculado no linker em tempo de compilação)
mas o ponteiro de função está atrasado vincular o fp pode chamar add ou sub dependendo da escolha do usuário [no tempo de execução].
Resposta
Apenas vinculação inicial e tardia faz sentido no contexto dos tipos e não da maneira como você o está descrevendo. Quase todas as linguagens modernas são digitadas no sentido de que todos os valores têm tipos fixos. A diferença surge quando olhamos para as linguagens com tipagem estática e dinâmica. Em linguagens digitadas dinamicamente, as variáveis não têm tipos, portanto podem se referir a valores de qualquer tipo e isso significa que quando você chama um método em um objeto referido por alguma variável, a única maneira de determinar se essa chamada é válida ou não é procure a classe do objeto e veja se esse método realmente existe. Isso permite algumas coisas interessantes, como adicionar novos métodos às classes em tempo de execução, porque a pesquisa do método real é adiada até o último momento. A maioria das pessoas chama esse estado de affairs late binding.
Em uma linguagem de tipo estático, as variáveis têm tipos e, uma vez declaradas, não podem referir-se a nenhum valor que não seja do mesmo tipo. Isso não é estritamente verdadeiro, mas vamos assumir por agora. Agora, se você sabe que a variável sempre fará referência a valores de um tipo específico, não há razão para descobrir se uma chamada de método é válida ou não em tempo de execução, porque você pode determinar a validade antes que o código seja executado. Isso é conhecido como vinculação inicial.
Um exemplo para demonstrar a vinculação tardia em ruby:
a = 1 # a is an integer at this point a.succ # asking for its successor is valid class A def method_a # some code end end a = A.new a.method_a # this is also valid a.succ # this is not valid class A # we can re-open the class and add a method def succ # some more code end end a.succ # now this is valid
A sequência de ações acima não é possível em uma linguagem como Java, onde todos os tipos são fixos em tempo de execução.
Resposta
Em vez de dar a você uma definição acadêmica I tentará mostrar algumas das diferenças usando um exemplo do mundo real usando VBA:
Ligação inicial:
Dim x As FileSystemObject Set x = New FileSystemObject Debug.Print x.GetSpecialFolder(0)
Isso requer que uma referência seja definida para o componente “Microsoft Scripting Runtime” no tempo de design . Tem a vantagem de receber uma mensagem de erro já em tempo de compilação quando você comete um erro de digitação em FileSystemObject
ou nomes de métodos como GetSpecialFolder
.
Vinculação tardia
Dim x As Object Set x = CreateObject("Scripting.FileSystemObject") Debug.Print x.GetSpecialFolder(0)
Isso não requer que uma referência seja definida de antemão, a criação da instância e o tipo determinação só acontecerá em tempo de execução. O compilador não reclamará em tempo de compilação quando você tentar chamar um método inexistente de x
, isso levará a um erro em tempo de execução apenas quando a linha específica for executada .
Portanto, a desvantagem da ligação tardia é que você não tem nenhuma verificação de tipo forte aqui. Mas essa também é a vantagem – digamos que você tenha um componente em que existem várias versões e cada versão mais recente fornece algumas funções adicionais. (Um exemplo do mundo real são os componentes do MS Office, como a interface COM do Excel). você escreve um código que funciona junto com todas essas versões – você pode primeiro determinar a versão do componente específico e, se descobrir que tem apenas uma versão mais antiga disponível, evite executar chamadas de funções que não funcionam com essa versão.
Resposta
Talvez o exemplo mais comum de ligação tardia seja a resolução de URLs da Internet. Ele oferece suporte a sistemas dinâmicos e sistemas grandes sem tentar vincular e vincular todos os sites do mundo antes de chegar a qualquer um, mas, por outro lado, gera alguma sobrecarga (pesquisa de DNS, muito menos roteamento de IP) no tempo de execução.
Por essa luz, a maioria das variedades de vinculação em ambientes de linguagem é mais ou menos precoce, em tempo de compilação ou de link.
Cada tipo tem custos e benefícios.
Comentários
- Você pode colocar uma referência para esta definição de vinculação?Não ouvi falar de resolução de endereços de internet como ” vinculativo “, embora, como vincular é o ato de resolver nomes, suponho que alguém tenha argumentado que o conceito de vinculação antecipada / tardia pode ser aplicado para resolver URI para endereços de Internet. Mas esta não é uma interpretação comum, e o conceito de vinculação antecipada / tardia é anterior à época em que os computadores eram comumente conectados à internet.
Deixe uma resposta