¿Por qué Clojure tiene 5 formas de definir una clase en lugar de solo una?
clojure-java-interop (2)
Clojure tiene gen-class, reify, proxy y también deftype y defrecord para definir nuevos tipos de datos tipo 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?
Esta es una mezcla de tres factores diferentes:
- El sistema de tipo particular de la jvm
- La necesidad de una semántica ligeramente diferente para diferentes casos de uso al definir tipos
- El hecho de que algunos de estos se desarrollaron antes, y algunos más tarde, a medida que el lenguaje ha evolucionado.
Entonces, primero, consideremos qué hacen estos. 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 se usan 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é tanto deftype como defrecord, dado 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 leer más, echa un vistazo a:
La página de tipos de datos de clojure.org
El hilo de grupo de google donde se introdujeron deftype y reify
La respuesta corta es que todos tienen diferentes y útiles propósitos. La complejidad se debe a la necesidad de interoperar eficazmente con las diferentes características de la JVM subyacente.
Si no necesita ninguna interoperabilidad Java , el 99% de las veces es mejor que se quede con el defrecord o un simple mapa de Clojure.
- Use defrecord si quiere usar protocolos
- De lo contrario, un mapa regular de Clojure es probablemente el más simple y comprensible.
Si sus necesidades son más complejas, el siguiente diagrama de flujo es una gran herramienta para explicar por qué elegiría una de estas opciones sobre las demás:
http://cemerick.com/2011/07/05/flowchart-for-choosing-the-right-clojure-type-definition-form/