Con el alcance dinámico, una persona que llama puede acceder a las variables de la persona que llama. Pseudo código C:
void foo()
{
print(x);
}
void bar()
{
int x = 42;
foo();
}
Como nunca he programado en un lenguaje que admita el alcance dinámico, me pregunto cuáles serían algunos casos de uso del mundo real para el alcance dinámico.
Respuestas:
Una aplicación muy útil del alcance dinámico es pasar parámetros contextuales sin tener que agregar nuevos parámetros explícitamente a cada función en una pila de llamadas
Por ejemplo, Clojure admite el alcance dinámico a través de la encuadernación , que se puede utilizar para reasignar temporalmente el valor de
*out*
impresión. Si vuelve a vincular*out*
, cada llamada a imprimir dentro del alcance dinámico del enlace se imprimirá en su nueva secuencia de salida. Muy útil si, por ejemplo, desea redirigir toda la salida impresa a algún tipo de registro de depuración.Ejemplo: en el siguiente código, la función do-stuff se imprimirá en la salida de depuración en lugar de la salida estándar, pero tenga en cuenta que no necesité agregar un parámetro de salida a do-stuff para habilitar esto ...
Tenga en cuenta que los enlaces de Clojure también son subprocesos locales, por lo que no tiene problemas con el uso concurrente de esta capacidad. Esto hace que los enlaces sean considerablemente más seguros que (ab) usando variables globales para el mismo propósito.
fuente
(Descargo de responsabilidad: nunca he programado en un lenguaje de alcance dinámico)
El alcance es mucho más fácil de implementar y potencialmente más rápido. Con el alcance dinámico, solo se necesita una tabla de símbolos (las variables actualmente disponibles). Simplemente lee de esta tabla de símbolos para todo.
Imagina en Python la misma función.
Cuando llamo a la barra, pongo x en la tabla de símbolos. Cuando llamo a foo, tomo la tabla de símbolos utilizada actualmente para la barra y la empujo a la pila. Luego llamo a foo, que le ha pasado x (probablemente se haya puesto en la nueva tabla de símbolos al llamar a la función). Después de salir de la función, tengo que destruir el nuevo alcance y restaurar el antiguo.
Con el alcance dinámico, esto no es necesario. Solo necesito conocer la instrucción a la que debo regresar cuando la función finaliza, ya que no se debe hacer nada en la tabla de símbolos.
fuente
El manejo de excepciones en la mayoría de los idiomas utiliza el alcance dinámico; cuando se produce una excepción, el control se transferirá nuevamente al controlador más cercano en la pila de activación (dinámica).
fuente
return
declaraciones en la mayoría de los idiomas usan el alcance dinámico, porque devuelven el control a la persona que llama en la pila?No estoy 100% seguro de si esto es una coincidencia exacta, pero creo que al menos se acerca lo suficiente en un sentido general para mostrar dónde puede ser útil para romper o cambiar las reglas de alcance.
El lenguaje Ruby viene con la clase de plantillas ERB, que por ejemplo en Rails se usa para generar archivos html. Si lo usa se ve así:
Las
binding
manos acceden a las variables locales a la llamada al método ERB, por lo que puede acceder a ellas y usarlas para completar la plantilla. (El código entre los EOF es una cadena, la parte entre <% =%> evaluada como código Ruby por ERB y declararía su propio alcance como una función)Un ejemplo de Rails lo demuestra aún mejor. En un controlador de artículos, encontrará algo como esto:
El archivo index.html.erb podría usar la variable local
@articles
como esta (en este caso, la creación de un objeto ERB y el enlace son manejados por el marco Rails, por lo que no lo verá aquí):Entonces, mediante el uso de una variable de enlace, Ruby permite ejecutar el mismo código de plantilla en diferentes contextos.
La clase ERB es solo un ejemplo de uso. Ruby permite en general obtener el estado real de ejecución con enlaces de variables y métodos mediante el uso del enlace Kernel #, que es muy útil en cualquier contexto en el que desee evaluar un método en un contexto diferente o desee mantener un contexto para su uso posterior.
fuente
Los casos de uso para el alcance dinámico son IHMO igual que para las variables globales. El alcance dinámico evita algunos de los problemas con las variables globales que permiten una actualización más controlada de la variable.
Algunos casos de uso que se me ocurren:
Por supuesto, el alcance dinámico no es "absolutamente obligatorio", pero alivia la carga de tener que pasar datos de vagabundeo a lo largo de la cadena de llamadas o tener que implementar proxies globales inteligentes y administradores de contexto.
Pero, una vez más, el alcance dinámico es útil cuando se trata de elementos que muchas veces se tratan como globales (registro, salida, asignación / gestión de recursos, etc.).
fuente
Prácticamente no hay ninguno. Espero que, por ejemplo, nunca use la misma variable dos veces.
Ahora, ¿cómo llamas a foo y bar desde la misma función?
Esto es efectivamente similar al simple uso de una variable global, y es malo por las mismas razones.
fuente
x = 42; foo(); x = '42'; bar();
?