¿Cuáles son algunas ventajas de duck-typing vs. static typing?


Estoy investigando y experimentando más con Groovy y estoy tratando de envolver mi mente en torno a los pros y los contras de implementar cosas en Groovy que no puedo/no puedo hacer en Java. La programación dinámica sigue siendo solo un concepto para mí, ya que he estado profundamente impregnado de lenguajes estáticos y fuertemente tipeados.

Groovy me da la capacidad de pato-tipo, pero realmente no puedo ver el valor. ¿Cómo es más productivo el duck-typing que el static typing? ¿Qué tipo de cosas puedo hacer en mi código práctica para ayudarme a captar los beneficios de la misma?

Hago esta pregunta con Groovy en mente, pero entiendo que no es necesariamente una pregunta Groovy, así que doy la bienvenida a las respuestas de todos los campos de código.

Author: codeLes, 2008-09-07

12 answers

A continuación, ¿cuál es mejor: EMACS o vi? Esta es una de las guerras religiosas en curso.

Piénsalo de esta manera: cualquier programa que sea correcto, será correcto si el lenguaje se escribe estáticamente. Lo que hace la escritura estática es dejar que el compilador tenga suficiente información para detectar desajustes de tipos en tiempo de compilación en lugar de tiempo de ejecución. Esto puede ser una molestia si está haciendo tipos incrementales de programación, aunque (mantengo) si está pensando claramente en su programa, no lo hace mucho importa; por otro lado, si estás construyendo un programa realmente grande, como un sistema operativo o un conmutador telefónico, con docenas o cientos o miles de personas trabajando en él, o con requisitos de confiabilidad realmente altos, entonces el compilador puede detectar una gran clase de problemas sin necesidad de un caso de prueba para ejercer la ruta de código correcta.

No es como si la escritura dinámica fuera una cosa nueva y diferente: C, por ejemplo, se escribe dinámicamente efectivamente, ya que Siempre puedo lanzar un foo* a un bar*. Solo significa que es entonces mi responsabilidad como programador de C nunca usar código que sea apropiado en un bar* cuando la dirección realmente apunta a un foo*. Pero como resultado de los problemas con programas grandes, C creció herramientas como lint(1), fortaleció su sistema de tipos con typedef y eventualmente desarrolló una variante fuertemente tipeada en C++. (Y, por supuesto, C++ a su vez desarrolló formas alrededor de la escritura fuerte, con todas las variedades de moldes y genéricos / plantillas y con RTTI.

Otra cosa, sin embargo --- no confundas "programación ágil" con "lenguajes dinámicos". Agile programming se trata de la forma en que las personas trabajan juntas en un proyecto: ¿puede el proyecto adaptarse a los requisitos cambiantes para satisfacer las necesidades de los clientes y mantener un entorno humano para los programadores? Se puede hacer con lenguajes dinámicamente tipeados, y a menudo lo es, porque pueden ser más productivos (por ejemplo, Ruby, Smalltalk), pero se puede hacer, se ha hecho con éxito, en C e incluso ensamblador. De hecho, Rally Development incluso utiliza métodos ágiles (SCRUM en particular) para hacer marketing y documentación.

 4
Author: Charlie Martin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-09 15:12:25

Muchos de los comentarios para duck typing realmente no corroboran las afirmaciones. No "tener que preocuparse" por un tipo no es sostenible para el mantenimiento o hacer que una aplicación sea extensible. Realmente he tenido una buena oportunidad de ver Grails en acción durante mi último contrato y es bastante divertido de ver realmente. Todo el mundo está contento con las ganancias en ser capaz de "crear-aplicación" y ponerse en marcha - tristemente todo te alcanza en el back-end.

A mí me parece lo mismo. Claro que puedes escribe un código muy sucinto y definitivamente hay algo de azúcar en la forma en que llegamos a trabajar con propiedades, colecciones, etc... Pero el costo de no saber qué diablos se está pasando de un lado a otro solo empeora y empeora. En algún momento te rascas la cabeza preguntándote por qué el proyecto se ha convertido en un 80% de pruebas y un 20% de trabajo. La lección aquí es que "más pequeño" no hace que el código sea "más legible". Lo sentimos gente, su lógica simple - cuanto más usted tiene que saber intuitivamente entonces el más complejo el proceso de entender que el código se convierte. Es por eso que las GUI se han vuelto demasiado icónicas a lo largo de los años - seguro que se ve bastante, pero lo que está pasando no siempre es obvio.

La gente en ese proyecto parecía tener problemas "clavando" las lecciones aprendidas, pero cuando tienes métodos que devuelven un solo elemento de tipo T, una matriz de T, un ErrorResult o un null ... se hace bastante evidente.

Una cosa que trabajar con Groovy ha hecho por mí sin embargo-impresionante ¡horas facturables woot!

 13
Author: Lypheus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-18 23:15:42

No hay nada malo con la escritura estática si está utilizando Haskell, que tiene un increíble sistema de tipos estáticos. Sin embargo, si está utilizando lenguajes como Java y C++ que tienen sistemas de tipos terriblemente paralizantes, duck typing es definitivamente una mejora.

Imagine intentar usar algo tan simple como " map" en Java (y no, no me refiero a la estructura de datos). Incluso los genéricos están bastante mal apoyados.

 9
Author: Nick Retallack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-16 23:44:47

Duck typing paraliza la comprobación estática del IDE más moderno, que puede señalar errores a medida que escribe. Algunos consideran esto una ventaja. Quiero que el IDE / Compilador me diga que he hecho un estúpido truco de programador tan pronto como sea posible.

Mi argumento favorito más reciente contra duck typing proviene de un DTO del proyecto Grails:

class SimpleResults {
    def results
    def total
    def categories
}

Donde results resulta ser algo así como Map<String, List<ComplexType>>, que se puede descubrir solo siguiendo un rastro de llamadas a métodos en diferentes clases hasta que encuentres donde fue creado. Para los curiosos terminales, total es la suma de los tamaños de los List<ComplexType>s y categories es el tamaño de los Map

Puede haber sido claro para el desarrollador original, pero el chico de mantenimiento pobre (YO) perdió mucho pelo rastreando este.

 7
Author: Ken Gentle,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-10-30 13:09:55

Es un poco difícil ver el valor de duck typing hasta que lo hayas usado por un tiempo. Una vez que te acostumbres a ello, te darás cuenta de la carga que supone no tener que lidiar con interfaces o tener que preocuparte por exactamente qué tipo es algo.

 6
Author: Jason Baker,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-07 00:42:26

EN mi humilde opinión, la ventaja de duck typing se magnifica cuando se adhieren a algunas convenciones, como nombrar variables y métodos de una manera consistente. Tomando el ejemplo de Ken G , creo que se leería mejor:

class SimpleResults {
    def mapOfListResults
    def total
    def categories
}

Digamos que usted define un contrato en alguna operación llamada 'calculateRating(A,B)' donde A y B se adhieren a otro contrato. En pseudocódigo, diría:

Long calculateRating(A someObj, B, otherObj) {

   //some fake algorithm here:
   if(someObj.doStuff('foo') > otherObj.doStuff('bar')) return someObj.calcRating());
   else return otherObj.calcRating();

}

Si desea implementar esto en Java, tanto A como B deben implementar algún tipo de interfaz que lee algo como esto:

public interface MyService {
    public int doStuff(String input);
}

Además, si quieres generalizar tu contrato para el cálculo de calificaciones (digamos que tienes otro algoritmo para el cálculo de calificaciones), también tienes que crear una interfaz:

public long calculateRating(MyService A, MyServiceB);

Con duck typing, puede deshacerse de sus interfaces y confiar en que en tiempo de ejecución, tanto A como B responderán correctamente a sus llamadas doStuff(). No hay necesidad de una definición específica del contrato. Esto puede funcionar para usted, pero también puede funcionar contra ti.

La desventaja es que debes tener mucho cuidado para garantizar que tu código no se rompa cuando otras personas lo cambien (es decir, la otra persona debe ser consciente del contrato implícito en el nombre del método y los argumentos).

Tenga en cuenta que esto se agrava especialmente en Java, donde la sintaxis no es tan concisa como podría ser (en comparación con Scala, por ejemplo). Un contra-ejemplo de esto es el Lift framework, donde dicen que el SLOC el conteo del framework es similar a Rails , pero el código de prueba tiene menos líneas porque no necesitan implementar comprobaciones de tipo dentro de las pruebas.

 3
Author: Miguel Ping,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-11-09 14:25:50

Aquí hay un escenario donde duck typing ahorra trabajo.

Aquí hay una clase muy trivial

class BookFinder {
    def searchEngine

    def findBookByTitle(String title) {
         return searchEngine.find( [ "Title" : title ] ) 
    }
}

Ahora para la prueba unitaria:

void bookFinderTest() {
    // with Expando we can 'fake' any object at runtime.
    // alternatively you could write a MockSearchEngine class.
    def mockSearchEngine = new Expando()
    mockSearchEngine.find = {
        return new Book("Heart of Darkness","Joseph Conrad")
    }

    def bf = new BookFinder()
    bf.searchEngine = mockSearchEngine
    def book = bf.findBookByTitle("Heart of Darkness")
    assert(book.author == "Joseph Conrad"
}

Pudimos sustituir el motor de búsqueda por un Expando, debido a la ausencia de comprobación de tipos estáticos. Con la comprobación de tipos estáticos habríamos tenido que asegurarnos de que SearchEngine fuera una interfaz, o al menos una clase abstracta, y crear una implementación simulada completa de la misma. Eso es mano de obra intensiva, o se puede utilizar un sofisticado marco burlón de propósito único. Pero el duck typing es de uso general, y nos ha ayudado.

Debido a la tipificación de duck, nuestra prueba unitaria puede proporcionar cualquier objeto antiguo en lugar de la dependencia, siempre y cuando implemente los métodos a los que se llama.

Para enfatizar - puede hacer esto en un lenguaje estáticamente tipado, con un uso cuidadoso de interfaces y jerarquías de clases. Pero con duck typing puedes hacerlo con menos pensamiento y menos pulsaciones de teclas.

Esa es una ventaja de pato teclear. Esto no significa que la escritura dinámica sea el paradigma correcto para usar en todas las situaciones. En mis proyectos Groovy, me gusta volver a Java en circunstancias en las que siento que las advertencias del compilador sobre los tipos van a ayudarme.

 2
Author: slim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-16 11:20:42

Con, TDD + 100% de Cobertura de código + herramientas IDE para ejecutar constantemente mis pruebas, ya no siento la necesidad de escribir estática. Sin tipos fuertes, mi prueba unitaria se ha vuelto tan fácil (Simplemente use Mapas para crear objetos simulados). Especialmente, cuando estás usando genéricos, puedes ver la diferencia:

//Static typing 
Map<String,List<Class1<Class2>>> someMap = [:] as HashMap<String,List<Class1<Class2>>>

Vs

//Dynamic typing
def someMap = [:]   
 2
Author: sukrit007,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-11-17 08:30:44

No es que el duck typing sea más productivo que el static typing, sino que es simplemente diferente. Con la escritura estática siempre tiene que preocuparse de que sus datos sean del tipo correcto y en Java se muestre a través de la conversión al tipo correcto. Con duck typing, el tipo no importa siempre y cuando tenga el método correcto, por lo que realmente solo elimina muchos de los problemas de casting y conversiones entre tipos.

 1
Author: Chris Bunch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-07 00:31:58

@Chris Bunch

No es que la escritura estática sea más productiva que la escritura de pato, sino que es simplemente diferente. Con duck typing siempre tiene que preocuparse de que sus datos tengan el método correcto y en Javascript o Ruby se muestra a través de muchas pruebas de métodos. Con la escritura estática no importa, siempre y cuando sea la interfaz correcta, por lo que realmente solo elimina una gran cantidad de la molestia de las pruebas y conversiones entre tipos.

Lo siento, pero tuve que hacerlo...
 1
Author: Vincent Robert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-07 01:08:15

Mi opinión:

Los lenguajes dinámicamente tipeados o duck typed son juguetes. No se puede obtener Intellisense y se pierde tiempo de compilación (o tiempo de edición - cuando se utiliza un IDE REAL como VS, no que la basura que otras personas piensan que son IDEs) validación de código.

Manténgase alejado de todo lenguaje que no esté escrito estáticamente, todo lo demás es simplemente masoquismo.

 1
Author: stormianrootsolver,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-09 11:13:01

Para mí, no son terriblemente diferentes si ves los lenguajes tipeados dinámicamente como simplemente una forma de escritura estática donde todo hereda de una clase base suficientemente abstracta.

Los problemas surgen cuando, como muchos han señalado, empiezas a ponerte extraño con esto. Alguien señaló una función que devuelve un solo objeto, una colección o un null. Haga que la función devuelva un tipo específico, no múltiples. El uso de múltiples funciones de sola vs colección.

Lo que hierve hasta es que cualquiera puede escribir código malo. La tipificación estática es un gran dispositivo de seguridad, pero a veces el casco se interpone cuando quieres sentir el viento en tu cabello.

 0
Author: Evan Langlois,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-18 06:53:44