language design - sistemas - Escribiendo pato, ¿debe ser dinámico?
introduccion a la dinamica de sistemas (8)
Sistema de tipo estructural
Un sistema de tipo estructural compara un tipo completo con otro para determinar si son compatibles. Para que dos tipos A
y B
sean compatibles, A
y B
deben tener la misma estructura, es decir, cada método en A
y en B
debe tener la misma firma.
Escribiendo pato
La tipificación de pato considera que dos tipos son equivalentes para la tarea en cuestión si ambos pueden manejar esa tarea. Para que dos tipos A
y B
sean equivalentes a un fragmento de código que desee escribir en un archivo, A
y B
deben implementar un método de escritura.
Resumen
Los sistemas de tipo estructural comparan cada firma de método (estructura completa). La tipificación de pato compara los métodos que son relevantes para una tarea específica (estructura relevante para una tarea).
Wikipedia solía decir * sobre duck-typing :
En la programación de computadoras con lenguajes de programación orientados a objetos, la escritura de pato es un estilo de escritura dinámica en el que el conjunto actual de métodos y propiedades de un objeto determina la semántica válida, en lugar de su herencia de una clase particular o la implementación de una interfaz específica.
(* Nota del editor: desde que se publicó esta pregunta, el artículo de Wikipedia se ha editado para eliminar la palabra "dinámico".)
Dice acerca de la tipificación estructural :
Un sistema de tipo estructural (o sistema de tipo basado en la propiedad) es una clase principal de sistema de tipo, en el que la compatibilidad y equivalencia de los tipos están determinadas por la estructura del tipo, y no a través de declaraciones explícitas.
Contrasta el subtipo estructural con la tipificación de pato como tal:
[Sistemas estructurales] contrasta con ... la escritura de pato, en la que solo se verifica la compatibilidad de la parte de la estructura a la que se accede en tiempo de ejecución.
Sin embargo, el término duck-typing me parece que al menos subsume intuitivamente los sistemas de sub-tipificación estructural. De hecho Wikipedia dice:
El nombre del concepto [tipografía de pato] se refiere a la prueba de pato , atribuida a James Whitcomb Riley, que puede expresarse de la siguiente manera: "cuando veo un pájaro que camina como un pato y nada como un pato y curanderos como un pato, Yo llamo pato a ese pájaro ".
Así que mi pregunta es: ¿por qué no puedo llamar subtitulación estructural? ¿Existen lenguajes tipificados dinámicamente que no puedan clasificarse también como tipificados de pato?
Posdata:
Como alguien llamado daydreamdrunk en reddit.com lo puso tan elocuentemente "Si se compila como un pato y se enlaza como un pato ..."
Post-postscript
Básicamente, muchas respuestas parecen simplemente repasar lo que ya he citado aquí, sin abordar la pregunta más profunda, ¿por qué no usar el término tipificación pato para cubrir tanto la tipificación dinámica como la subclasificación estructural? Si solo quiere hablar de tipificación de pato y no de subtitulación estructural, simplemente llámelo como es: búsqueda dinámica de miembros . Mi problema es que nada del término "tipificación de pato" me dice que esto solo se aplica a lenguajes dinámicos.
Entiendo que la tipificación estructural es utilizada por los inferentes de tipo y similares para determinar la información de tipo (piense en Haskell o OCaml), mientras que a la tipografía de pato no le interesan los "tipos" per se, solo que la cosa puede manejar una invocación de método específica / acceso a la propiedad, etc. (piense respond_to?
en Ruby o verificación de capacidades en Javascript).
Escribir pato significa que si se ajusta, está bien
Esto se aplica tanto a los tipos dinámicamente
def foo obj
obj.quak()
end
o lenguajes compilados estáticamente escritos
template <typename T>
void foo(T& obj) {
obj.quak();
}
El punto es que en ambos ejemplos, no ha habido ninguna información sobre el tipo dado. Justo cuando se usa (ya sea en tiempo de ejecución o en tiempo de compilación), los tipos se verifican y, si se cumplen todos los requisitos, el código funciona. Los valores no tienen un tipo explícito en su punto de declaración.
La tipificación estructural se basa en la escritura explícita de sus valores, como de costumbre. La diferencia es que el tipo concreto no se identifica por herencia sino por su estructura.
Un código estructurado (estilo Scala) para el ejemplo anterior sería
def foo(obj : { def quak() : Unit }) {
obj.quak()
}
No confunda esto con el hecho de que algunos lenguajes de tipo estructurado como OCaml combinan esto con la inferencia de tipos para evitar que definamos los tipos explícitamente.
Hay situaciones en las que la tipificación dinámica de pato y el código similar estático (en C ++) se comportan de manera diferente:
template <typename T>
void foo(T& obj) {
if(obj.isAlive()) {
obj.quak();
}
}
En C ++, el objeto debe tener los métodos isAlive
y quak
para que el código se compile; para el código equivalente en idiomas tipificados dinámicamente, el objeto solo necesita tener el método isAlive()
si isAlive()
devuelve true. Interpreto esto como una diferencia entre la estructura (tipificación estructural) y el comportamiento (tipificación duck).
(Sin embargo, llegué a esta interpretación tomando el valor nominal de "la tipificación del pato debe ser dinámica" de Wikipedia y tratando de que tenga sentido. La interpretación alternativa de que la tipificación estructural implícita es la tipificación del pato también es coherente).
Las plantillas C ++ y D son un ejemplo perfecto de escritura de pato que no es dinámica. Definitivamente es:
escribiendo en el que el conjunto actual de métodos y propiedades de un objeto determina la semántica válida, en lugar de su herencia de una clase particular o implementación de una interfaz específica.
No especifica explícitamente una interfaz de la que deba heredar su tipo para crear una instancia de la plantilla. Solo necesita tener todas las características que se usan dentro de la definición de la plantilla. Sin embargo, todo se resuelve en el momento de la compilación y se compila a números hexadecimales inescrutables y sin formato. Yo lo llamo "compilación de pato de tiempo". Desde esta mentalidad, he escrito bibliotecas enteras que la creación de instancias de plantillas implícitas es compilación en tiempo real y creo que es una de las características más subestimadas del mercado.
No estoy seguro de si realmente responde a tu pregunta, pero ...
El código C ++ templado se parece mucho a la tipificación de pato, pero es estático, de compilación y estructural.
template<typename T>
struct Test
{
void op(T& t)
{
t.set(t.get() + t.alpha() - t.omega(t, t.inverse()));
}
};
Siempre habrá ejemplos de algunos lenguajes de programación que violan algunas definiciones de varios términos. Por ejemplo, ActionScript admite la programación de estilo de escritura de pato en instancias que no son técnicamente dinámicas.
var x:Object = new SomeClass();
if ("begin" in x) {
x.begin();
}
En este caso, probamos si la instancia del objeto en "x" tiene un método "begin" antes de llamarlo en lugar de usar una interfaz. Esto funciona en ActionScript y es bastante tipográfico, aunque la clase SomeClass () puede no ser dinámica.
Veo "tipografía de pato" más como un estilo de programación, mientras que "tipificación estructural" es una característica del sistema tipográfico.
La tipificación estructural se refiere a la capacidad del sistema de tipos para expresar tipos que incluyen todos los valores que tienen ciertas propiedades estructurales.
La escritura de pato se refiere a la escritura de código que solo usa las características de los valores que se pasan y que realmente se necesitan para el trabajo en cuestión, sin imponer ninguna otra restricción.
Así que podría usar tipos estructurales para codificar en un estilo de escritura de pato, declarando formalmente mis "tipos de pato" como tipos estructurales. Pero también podría usar tipos estructurales sin "escribir pato". Por ejemplo, si escribo interfaces a un grupo de funciones / métodos / procedimientos / predicados / clases relacionadas, declarando y nombrando un tipo estructural común y luego usándolo en todas partes, es muy probable que algunas de las unidades de código no sean necesarias. todas las características del tipo estructural, por lo que he restringido innecesariamente a algunas de ellas para que rechacen valores en los que teóricamente podrían funcionar correctamente.
Entonces, si bien puedo ver que hay puntos en común, no creo que la tipificación de pato subsume la tipificación estructural. De la forma en que pienso en ellos, la tipificación de pato no es una cosa que podría haber sido capaz de subsumir tipificación estructural, porque no son el mismo tipo de cosas. Pensar en la escritura de pato en lenguajes dinámicos como simplemente "tipos estructurales implícitos, sin marcar" falta algo, IMHO. La escritura de pato es un estilo de codificación que elige utilizar o no, no solo una característica técnica de un lenguaje de programación.
Por ejemplo, es posible usar isinstance
verificaciones de isinstance
en Python para falsificar las restricciones de tipo "clase o subclase" de estilo OO. También es posible verificar atributos y métodos particulares, para simular restricciones de tipo estructural (incluso se podrían poner los controles en una función externa, obteniendo así un tipo estructural nombrado). Yo diría que ninguna de estas opciones es un ejemplo de tipificación de pato (a menos que los tipos estructurales sean muy finos y se mantengan en estrecha sincronía con el código que los verifica).