En informática , el enlace tardío o enlace dinámico [1] —aunque no es un proceso idéntico al enlace dinámico de bibliotecas de código importadas— es un mecanismo de programación informática en el que el método que se llama en un objeto , o la función que se llama con argumentos, se busca por nombre en tiempo de ejecución . En otras palabras, un nombre se asocia con una operación u objeto en particular en tiempo de ejecución, en lugar de durante la compilación . El nombre enlace dinámico se utiliza a veces, [2] pero se usa más comúnmente para referirse al alcance dinámico .
Con la vinculación temprana , o vinculación estática , en un lenguaje orientado a objetos , la fase de compilación fija todos los tipos de variables y expresiones . Esto generalmente se almacena en el programa compilado como un desplazamiento en una tabla de métodos virtuales ("v-table"). [3] Por el contrario, con la vinculación tardía, el compilador no lee suficiente información para verificar que el método existe o vincular su ranura en la v-table. En cambio, el método se busca por nombre en tiempo de ejecución.
La principal ventaja de utilizar el enlace tardío en la programación del Modelo de objetos componentes (COM) es que no requiere que el compilador haga referencia a las bibliotecas que contienen el objeto en el momento de la compilación . Esto hace que el proceso de compilación sea más resistente a los conflictos de versiones, en los que la tabla virtual de la clase puede modificarse accidentalmente. (Esto no es un problema en plataformas compiladas justo a tiempo como .NET o Java , porque la tabla virtual se crea en tiempo de ejecución por la máquina virtual contra las bibliotecas a medida que se cargan en la aplicación en ejecución. [4] )
El término "enlace tardío" se remonta al menos a la década de 1960, cuando se lo puede encontrar en Communications of the ACM . El término se utilizó ampliamente para describir las convenciones de llamadas en lenguajes como Lisp, aunque generalmente con connotaciones negativas sobre el rendimiento. [5]
En la década de 1980, Smalltalk popularizó la programación orientada a objetos (POO) y, con ella, la vinculación tardía. Alan Kay dijo una vez: "Para mí, la POO significa únicamente mensajería, retención local, protección y ocultación de procesos de estado y vinculación tardía extrema de todas las cosas. Se puede hacer en Smalltalk y en LISP. Es posible que existan otros sistemas en los que esto sea posible, pero no los conozco". [6]
A principios y mediados de la década de 1990, Microsoft promovió intensamente su estándar COM como una interfaz binaria entre diferentes lenguajes de programación OOP. La programación COM promovió por igual el enlace temprano y tardío, y muchos lenguajes admitían ambos a nivel de sintaxis.
En 2000, Alex Martelli acuñó el término " tipificación pato " para referirse a un concepto similar, pero con un énfasis diferente. Mientras que la vinculación tardía generalmente se centra en los detalles de implementación, la tipificación pato se centra en la capacidad de ignorar los tipos y concentrarse en los métodos que tiene actualmente un objeto.
En la mayoría de los lenguajes de tipado dinámico , la lista de métodos de un objeto se puede modificar en tiempo de ejecución. Esto requiere una vinculación tardía.
En Lisp , las llamadas a funciones globales con enlaces tardíos se buscan de manera eficiente en tiempo de ejecución a través de la celda de función de un símbolo . Estos enlaces de función son mutables.
Ejemplo que utiliza una sesión interactiva de Clozure Common Lisp :
? ( defun foo () ( bar pi )) ; se llama a una función BAR aún no definida ; Advertencias del compilador : ; En FOO: Función no definida BAR FOO ? ( defun bar ( x ) ; ahora lo definimos ( * x 2 )) BAR ? ( foo ) ; llama a foo y utiliza la definición reciente de BAR 6.283185307179586D0 ? ( defun bar ( x ) ; ahora redefinimos BAR ( * x 1000 )) BAR ? ( foo ) ; FOO ahora llama a la nueva función, no hay necesidad de volver a compilar/vincular/cargar FOO 3141.592653589793D0 ? ( tipo de 'barra ') ; BAR es un símbolo SÍMBOLO ? ( símbolo-función 'barra ) ; el símbolo BAR tiene un enlace de función # <Función compilada BAR #x302000D1B21F >
En C++, el enlace tardío (también llamado "enlace dinámico") se refiere a lo que normalmente sucede cuando virtual
se utiliza la palabra clave en la declaración de un método. C++ crea entonces una denominada tabla virtual , que es una tabla de búsqueda para dichas funciones que siempre se consultarán cuando se las llame. [7] Por lo general, el término "enlace tardío" se utiliza en favor del " envío dinámico ".
En la programación COM, una llamada a un método enlazado en tiempo de ejecución se realiza mediante la interfaz IDispatch . Algunos lenguajes basados en COM, como Visual Basic 6, tienen soporte sintáctico para llamar a esta interfaz. [8] Esto se hace definiendo el tipo de la variable como Object. Otros, como C++, requieren que se llame explícitamente a GetIDsOfNames para buscar un método y a Invoke para llamarlo.
En .NET, el enlace tardío se refiere a la anulación de un virtual
método como en C++ o la implementación de una interfaz. El compilador crea tablas virtuales para cada llamada a un método virtual o de interfaz que se utiliza en tiempo de ejecución para determinar la implementación que se ejecutará.
Al igual que COM y Java, Common Language Runtime ofrece API de reflexión que pueden realizar llamadas de enlace tardías. El uso de estas llamadas varía según el lenguaje.
Con C# 4, el lenguaje también agregó el pseudotipo "dinámico". Este se usaría en lugar del tipo Object para indicar que se desea un enlace tardío. El mecanismo de enlace tardío específico que se necesita se determina en tiempo de ejecución utilizando Dynamic Language Runtime como punto de partida.
Visual Basic los utiliza siempre que la variable sea de tipo Object y esté en vigor la directiva del compilador "Option Strict Off". Esta es la configuración predeterminada para un nuevo proyecto de VB. Antes de la versión 9, solo los objetos .NET y COM podían enlazarse en tiempo de ejecución. Con VB 10, esto se ha ampliado a los objetos basados en DLR.
Hay tres definiciones de enlace tardío en Java.
Los primeros documentos sobre Java hablaban de que las clases no se vinculaban entre sí en tiempo de compilación. Si bien los tipos se comprueban estáticamente en tiempo de compilación, las diferentes implementaciones de las clases se podían intercambiar justo antes del tiempo de ejecución simplemente sobrescribiendo el archivo de clase. Mientras la nueva definición de clase tuviera los mismos nombres de clase y método, el código seguiría funcionando. En este sentido, es similar a la definición tradicional de vinculación tardía.
Actualmente, es popular utilizar el término enlace tardío en la programación Java como sinónimo de despacho dinámico . En concreto, esto se refiere al mecanismo de despacho único de Java utilizado con métodos virtuales.
Finalmente, Java puede utilizar el enlace tardío mediante sus API de reflexión y la introspección de tipos de la misma forma que se hace en la programación COM y .NET. En términos generales, quienes solo programan en Java no llaman a este enlace tardío. Asimismo, el uso de técnicas de "tipado pato" está mal visto en la programación Java, y en su lugar se utilizan interfaces abstractas.
Se sabe que Oracle, el actual propietario de Java, ha utilizado el término enlace tardío en el sentido de "tipado de pato" cuando analiza tanto Java como otros lenguajes en la misma documentación. [9]
Cuando se utiliza un enlace temprano entre Ada y un procedimiento almacenado en una base de datos, se comprueba una marca de tiempo para verificar que el procedimiento almacenado no haya cambiado desde que se compiló el código. Esto permite ejecuciones más rápidas y evita que la aplicación se ejecute con la versión incorrecta de un procedimiento almacenado. [10]
Cuando se utiliza el enlace tardío, no se realiza la comprobación de la marca de tiempo y el procedimiento almacenado se ejecuta a través de un bloque PL/SQL anónimo. Si bien esto puede ser más lento, elimina la necesidad de volver a compilar todas las aplicaciones cliente cuando cambia un procedimiento almacenado.
Esta distinción parece ser exclusiva de PL/SQL y Ada. Otros lenguajes que pueden llamar a procedimientos PL/SQL, así como otros motores de bases de datos, solo utilizan el enlace tardío.
La vinculación tardía tiene un rendimiento más bajo que una llamada a un método vinculada de forma anticipada. En la mayoría de las implementaciones, se debe buscar la dirección correcta del método por nombre con cada llamada, lo que requiere una búsqueda en diccionario relativamente costosa y posiblemente una lógica de resolución de sobrecarga. En la mayoría de las aplicaciones, el tiempo y los cálculos adicionales requeridos son insignificantes en las computadoras modernas.
En el caso de algunos compiladores, la vinculación tardía puede impedir el uso de la comprobación de tipos estáticos. Al realizar una llamada de vinculación tardía, el compilador debe asumir que el método existe. Esto significa que un simple error de ortografía puede provocar que se genere un error en tiempo de ejecución. Los compiladores modernos evitan esto al garantizar que cada llamada posible debe tener una implementación durante la compilación.
La vinculación tardía puede impedir formas de análisis estático necesarias para un entorno de desarrollo integrado (IDE). Por ejemplo, la característica "ir a la definición" de un IDE puede no funcionar en una llamada vinculada tardíamente, si el IDE no tiene forma de saber a qué clase puede hacer referencia la llamada. Un IDE moderno resuelve esto fácilmente, especialmente para lenguajes orientados a objetos, ya que un método vinculado tardíamente siempre especifica una interfaz o clase base, que es a donde conduce "ir a la definición", y "buscar todas las referencias" se puede utilizar para encontrar todas las implementaciones o anulaciones. [11]