stringtranslate.com

Lenguaje de programación dinámica

Un lenguaje de programación dinámico es un tipo de lenguaje de programación que permite determinar y ejecutar varias operaciones en tiempo de ejecución. Esto es diferente de la fase de compilación. Las decisiones clave sobre variables, llamadas a métodos o tipos de datos se toman cuando el programa se está ejecutando, a diferencia de los lenguajes estáticos , donde la estructura y los tipos se fijan durante la compilación. Los lenguajes dinámicos brindan flexibilidad. Esto permite a los desarrolladores escribir código más adaptable y conciso.

Por ejemplo, en un lenguaje dinámico, una variable puede comenzar como un entero y luego puede reasignarse para contener una cadena sin declaraciones de tipo explícitas. Esta característica de tipado dinámico permite una codificación más fluida y menos restrictiva. Los desarrolladores pueden centrarse en la lógica y la funcionalidad en lugar de en las limitaciones del lenguaje.

Implementación

Evaluar

Algunos lenguajes dinámicos ofrecen una función eval . Esta función toma una cadena o un árbol de sintaxis abstracta que contiene código en el lenguaje y lo ejecuta. Si este código representa una expresión, se devuelve el valor resultante. Erik Meijer y Peter Drayton distinguen la generación de código en tiempo de ejecución que ofrece eval de la carga dinámica que ofrecen las bibliotecas compartidas , y advierten que en muchos casos eval se utiliza simplemente para implementar funciones de orden superior (pasando funciones como cadenas) o deserialización . [1]

Alteración del tiempo de ejecución de un objeto

En un lenguaje dinámico, un sistema de tipos o de objetos se puede modificar durante el tiempo de ejecución. Esto puede significar generar nuevos objetos a partir de una definición en tiempo de ejecución o en función de combinaciones de tipos u objetos existentes. Esto también puede hacer referencia a cambiar la herencia o el árbol de tipos y, por lo tanto, alterar la forma en que se comportan los tipos existentes (especialmente con respecto a la invocación de métodos ).

Inferencia de tipos

Como muchos lenguajes dinámicos vienen con un sistema de tipos dinámico, la inferencia de tipos en tiempo de ejecución basada en valores para la interpretación interna es una tarea común. Como los tipos de valores pueden cambiar durante la interpretación, se utiliza con regularidad al realizar operaciones atómicas.

Asignación de memoria variable

Los lenguajes de programación estáticos (posiblemente de manera indirecta) requieren que los desarrolladores definan el tamaño de la memoria utilizada antes de la compilación (a menos que se trabaje con lógica de punteros). En consonancia con la alteración del tiempo de ejecución de los objetos, los lenguajes dinámicos necesitan implícitamente (reasignar) la memoria en función de las operaciones individuales del programa.

Reflexión

La reflexión es común en muchos lenguajes dinámicos y normalmente implica el análisis de los tipos y metadatos de datos genéricos o polimórficos . Sin embargo, también puede incluir la evaluación y modificación completas del código de un programa como datos, como las funciones que ofrece Lisp para analizar expresiones S.

Macros

Un número limitado de lenguajes de programación dinámicos proporcionan características que combinan la introspección de código (la capacidad de examinar clases, funciones y palabras clave para saber qué son, qué hacen y qué saben) y la evaluación en una característica llamada macros . La mayoría de los programadores actuales que conocen el término macro las han encontrado en C o C++ , donde son una característica estática que está incorporada en un pequeño subconjunto del lenguaje y solo son capaces de realizar sustituciones de cadenas en el texto del programa. En los lenguajes dinámicos, sin embargo, brindan acceso al funcionamiento interno del compilador y acceso completo al intérprete, la máquina virtual o el entorno de ejecución, lo que permite la definición de construcciones similares a las del lenguaje que pueden optimizar el código o modificar la sintaxis o la gramática del lenguaje.

En general, Assembly , C , C++ , Java temprano y Fortran no encajan en esta categoría. [ aclaración necesaria ]

Código de ejemplo

Los siguientes ejemplos muestran características dinámicas utilizando el lenguaje Common Lisp y su Common Lisp Object System (CLOS).

Cálculo de código en tiempo de ejecución y vinculación tardía

El ejemplo muestra cómo se puede modificar una función en tiempo de ejecución a partir del código fuente calculado

; el código fuente se almacena como datos en una variable CL-USER > ( defparameter *best-guess-formula* ' ( lambda ( x ) ( * x x 2.5 ))) *BEST-GUESS-FORMULA*         ; se crea una función a partir del código y se compila en tiempo de ejecución, la función está disponible con el nombre best-guess CL-USER > ( compile 'best-guess *best-guess-formula* ) # <Función 15 40600152F4>      ; la función se puede llamar CL-USER > ( mejor estimación 10.3 ) 265.225   ; el código fuente podría mejorarse en tiempo de ejecución CL-USER > ( setf *best-guess-formula* ` ( lambda ( x ) , ( list 'sqrt ( third *best-guess-formula* )))) ( LAMBDA ( X ) ( SQRT ( * X X 2.5 )))               ; se está compilando una nueva versión de la función CL-USER > ( compile 'best-guess *best-guess-formula* ) # <Función 16 406000085C>      ; la siguiente llamada llamará a la nueva función, una característica del enlace tardío CL-USER > ( mejor estimación 10.3 ) 16.28573   

Alteración del tiempo de ejecución de un objeto

Este ejemplo muestra cómo se puede cambiar una instancia existente para incluir un nuevo espacio cuando cambia su clase y cómo se puede reemplazar un método existente con una nueva versión.

; una clase de persona. La persona tiene un nombre. CL-USER > ( defclass person () (( name :initarg :name ))) # <STANDARD-CLASS PERSON 4020081FB3>         ; un método de impresión personalizado para los objetos de la clase persona CL-USER > ( defmethod print-object (( p person ) stream ) ( print-unreadable-object ( p stream :type t ) ( format stream "~a" ( slot-value p 'name )))) # <STANDARD-METHOD PRINT-OBJECT NIL ( PERSON T ) 4020066E5B>                      ; un ejemplo de instancia de persona CL-USER > ( setf *person-1* ( make-instance 'person :name "Eva Luator" )) # <PERSON Eva Luator>         ; la clase persona obtiene un segundo espacio. Luego tiene el nombre y la edad de los espacios. CL-USER > ( defclass person () (( name :initarg :name ) ( age :initarg :age :initform :unknown ))) # <STANDARD-CLASS PERSON 4220333E23>              ; actualizando el método para imprimir el objeto CL-USER > ( defmethod print-object (( p person ) stream ) ( print-unreadable-object ( p stream :type t ) ( format stream "~a age: ~" ( slot-value p 'name ) ( slot-value p 'age )))) # <STANDARD-METHOD PRINT-OBJECT NIL ( PERSON T ) 402022ADE3>                         ; el objeto existente ahora ha cambiado, tiene una ranura adicional y un nuevo método de impresión CL-USER > *person-1* # <PERSON Eva Luator age: UNKNOWN>      ; podemos establecer el nuevo intervalo de edad de la instancia CL-USER > ( setf ( slot-value *person-1* 'age ) 25 ) 25      ; el objeto ha sido actualizado CL-USER > *person-1* # <PERSON Eva Luator edad: 25>      

let foo = 42; // foo ahora es un número foo = "bar"; // foo ahora es una cadena foo = true; // foo ahora es un booleano

Ensamblaje de código en tiempo de ejecución en función de la clase de instancias

En el siguiente ejemplo, la clase person obtiene una nueva superclase. El método print se redefine de forma que reúne varios métodos en el método efectivo. El método efectivo se reúne en función de la clase del argumento y los métodos disponibles y aplicables en tiempo de ejecución.

; la clase persona CL-USER > ( defclass persona () (( nombre :initarg :nombre ))) # <STANDARD-CLASS PERSON 4220333E23>         ; una persona simplemente imprime su nombre CL-USER > ( defmethod print-object (( p person ) stream ) ( print-unreadable-object ( p stream :type t ) ( format stream "~a" ( slot-value p 'name )))) # <STANDARD-METHOD PRINT-OBJECT NIL ( PERSON T ) 40200605AB>                      ; una instancia de persona CL-USER > ( defparameter *person-1* ( make-instance 'person :name "Eva Luator" )) *PERSON-1*       ; mostrando una instancia de persona CL-USER > *person-1* # <PERSON Eva Luator>    ; ahora se redefine el método de impresión para que sea extensible ; el método around crea el contexto para el método de impresión y llama al siguiente método CL-USER > ( defmethod print-object :around (( p person ) stream ) ( print-unreadable-object ( p stream :type t ) ( call-next-method ))) # <STANDARD-METHOD PRINT-OBJECT ( :AROUND ) ( PERSON T ) 4020263743>                  ; el método principal imprime el nombre CL-USER > ( defmethod print-object (( p person ) stream ) ( format stream "~a" ( slot-value p 'name ))) # <STANDARD-METHOD PRINT-OBJECT NIL ( PERSON T ) 40202646BB>                 ; una nueva clase id-mixin proporciona un id CL-USER > ( defclass id-mixin () (( id :initarg :id ))) # <STANDARD-CLASS ID-MIXIN 422034A7AB>         ; el método de impresión simplemente imprime el valor de la ranura de identificación CL-USER > ( defmethod print-object :after (( object id-mixin ) stream ) ( format stream " ID: ~a" ( slot-value object 'id ))) # <STANDARD-METHOD PRINT-OBJECT ( :AFTER ) ( ID-MIXIN T ) 4020278E33>                  ; ahora redefinimos la clase persona para incluir el id-mixin CL-USER 241 > ( defclass persona ( id-mixin ) (( nombre :initarg :nombre ))) # <STANDARD-CLASS PERSON 4220333E23>          ; la instancia existente *person-1* ahora tiene un nuevo espacio y lo configuramos en 42 CL-USER 242 > ( setf ( slot-value *person-1* 'id ) 42 ) 42       ; mostrando el objeto nuevamente. La función print-object ahora tiene un método efectivo, que llama a tres métodos: un método around, el método primary y el método after. CL-USER 243 > *person-1* # <PERSON Eva Luator ID: 42>       

Ejemplos

Los lenguajes de programación dinámica más populares son JavaScript , Python , Ruby , PHP , Lua y Perl . Los siguientes se consideran lenguajes dinámicos en general:

Véase también

Referencias

  1. ^ Meijer, Erik y Peter Drayton (2005), Tipado estático cuando sea posible, tipado dinámico cuando sea necesario: el fin de la guerra fría entre lenguajes de programación (PDF) , Microsoft Corporation, CiteSeerX  10.1.1.69.5966
  2. ^ Capítulo 24. Compatibilidad dinámica con lenguajes. Static.springsource.org. Recuperado el 17 de julio de 2013.
  3. ^ < "Groovy - Home". Archivado desde el original el 2014-03-02 . Consultado el 2014-03-02 .

Lectura adicional

Enlaces externos

(Muchos utilizan el término "lenguajes de script").