Clojure tiene gen-class, reify, proxy y también deftype y defrecord para definir nuevos tipos de datos de clase. Para un lenguaje que valora la simplicidad sintáctica y aborrece la complejidad innecesaria, parece una aberración. ¿Podría alguien explicar por qué es así? ¿Podría bastar el defclass del estilo de Lisp común?¿Por qué Clojure tiene 5 formas de definir una clase en lugar de solo una?
Respuesta
Esta es una mezcla de tres factores diferentes:
- El sistema tipo particular de la JVM
- La necesidad de semántica ligeramente diferente para diferentes casos de uso en la definición de tipos
- El hecho de que algunos de estos se desarrollaron antes, y algunos más tarde, a medida que el lenguaje ha evolucionado.
Primero, consideremos qué hacen. deftype y gen-class son similares en el sentido de que ambos definen una clase con nombre para la compilación anticipada. Gen-class fue primero, seguido de deftype en clojure 1.2. Se prefiere Deftype y tiene mejores características de rendimiento, pero es más restrictivo. Una clase deftype puede ajustarse a una interfaz, pero no puede heredar de otra clase.
Reify y proxy de se utilizan tanto para crear dinámicamente una instancia de una clase anónima en tiempo de ejecución. Proxy fue el primero, reify vino junto con deftype y defrecord en clojure 1.2. Se prefiere Reify, al igual que deftype, donde la semántica no es demasiado restrictiva.
Eso deja la pregunta de por qué deftype y defrecord, ya que aparecieron al mismo tiempo, y tienen un rol similar. Para la mayoría de los propósitos, querremos usar defrecord: tiene todas las bondades de clojure que conocemos y amamos, sequability y demás. Deftype está diseñado para ser utilizado como un bloque de construcción de bajo nivel para la implementación de otras estructuras de datos. No incluye las interfaces regulares de clojure, pero tiene la opción de campos mutables (aunque esto no es lo predeterminado).
Para la lectura adicional Salida:
The clojure.org datatypes page
The google group thread where deftype and reify were introduced
La respuesta corta es que todos ellos tienen propósitos diferentes y útiles. La complejidad se debe a la necesidad de interoperar eficazmente con las diferentes características de la JVM subyacente.
Si no necesita ninguna interpo de Java, entonces el 99% de las veces es mejor que se quede con cualquiera de los defrecord o un simple mapa de Clojure.
- Uso defrecord si desea utilizar protocolos
- De lo contrario un mapa regular de Clojure es probablemente más simple y comprensible
Si sus necesidades son más complejas, a continuación, el siguiente diagrama de flujo es una gran herramienta para explicar por qué se elige una de estas opciones sobre los demás:
http://cemerick.com/2011/07/05/flowchart-for-choosing-the-right-clojure-type-definition-form/
muchas gracias por el enlace al diagrama de flujo. Ayuda que el blog sea del coautor de O'reilly's - Programming Clojure. Creo que esta toma de decisiones es bastante compleja. ¿Las diferencias entre la interfaz y la clase concreta o la necesidad de definir métodos estáticos o no, o el tipo con nombre o el tipo anónimo son tan vastos que necesitan una construcción de lenguaje diferente? – Salil
las diferencias no son grandes, pero son * filosóficamente diferentes * en términos de lo que estás tratando de lograr. Creo que los enfoques múltiples en Clojure reflejan estas diferencias subyacentes, que es una buena razón por la que se les debe dar diferentes nombres. – mikera
+1. No había visto ese diagrama de flujo antes, eso es increíble. –
- 1. Por qué solo una clase por archivo
- 2. En Clojure, ¿cómo definir una variable nombrada por una cadena?
- 3. ¿Por qué una int en OCaml solo tiene 31 bits?
- 4. 5 formas de utilizar la palabra clave estática en Java
- 5. ¿Cómo puedo definir una función en Clojure?
- 6. ¿Puedo definir un __repr__ para una clase en lugar de una instancia?
- 7. ¿Por qué Python tiene un método de operador __ne__ en lugar de solo __eq__?
- 8. ¿Por qué ArrayList no tiene getSize() en lugar de size()?
- 9. ¿Por qué la siguiente clase tiene una tabla virtual?
- 10. ¿Por qué utilizar una oreja en lugar de una guerra?
- 11. Definir una clase en un JSP
- 12. ¿Por qué Java tiene NullPointerException en lugar de NullReferenceException?
- 13. ¿Por qué usar una clase abstracta vacía en lugar de una interfaz?
- 14. ¿Por qué elegir una clase estática en lugar de una implementación singleton?
- 15. ¿Hay más formas de definir una tupla con un solo elemento?
- 16. ¿Por qué Clojure tiene "palabras clave" además de "símbolos"?
- 17. ¿Qué significa definir constantes en una interfaz?
- 18. ¿Por qué sellar una clase?
- 19. ¿Qué dos puntos (:) significa definir una clase en C#?
- 20. ¿Por qué JPA tiene una anotación @Transient?
- 21. Obtenga solo una clase en particular usando $ (this) .attr ("clase") en lugar de múltiples clases
- 22. ¿Por qué analizadores sintácticos en lugar de solo analizadores configurables?
- 23. formas recomendadas para depurar funciones Clojure?
- 24. Cómo definir una clase en Python
- 25. En Clojure, ¿es posible definir una función anónima dentro de una función anónima?
- 26. ¿Por qué las expresiones de cálculo F # requieren un objeto constructor (en lugar de una clase)?
- 27. ¿Por qué utilizar singleton en lugar de clase estática?
- 28. ¿Qué hace una clase de personaje con solo un caret?
- 29. ¿Por qué una clase de plantilla derivada no tiene acceso a los identificadores de una clase de plantilla base?
- 30. selector de "Definir" elemento de menú Editar en IOS 5
El hilo de grupo de Google fue muy valioso. Mi entendimiento es para el proxy java interoperabilidad, gen-class son suplantados por reify y deftype principalmente. Me alegro de que tengamos menos formas "recomendadas" para definir tipos ahora. – Salil
Excelente respuesta y gracias por el enlace de la secuencia. –
Lo sentimos, ¿qué significa "sequability"? Google no está ayudando ... – Trylks