Perché Clojure ha 5 modi per definire una classe invece di uno solo?


84

Clojure ha gen-class, reify, proxy e anche deftype e defrecord per definire nuovi tipi di dati di tipo classe. Per un linguaggio che valorizza la semplicità sintattica e detesta la complessità inutile, sembra un'aberrazione. Qualcuno potrebbe spiegare perché è così? Poteva essere sufficiente la defclass in stile Common Lisp?

Risposte:


91

Questo è un mix di tre diversi fattori:

  1. Il particolare sistema di tipi di jvm
  2. La necessità di una semantica leggermente diversa per diversi casi d'uso durante la definizione dei tipi
  3. Il fatto che alcuni di questi siano stati sviluppati prima e altri in seguito, man mano che il linguaggio si è evoluto.

Quindi prima, consideriamo cosa fanno. deftype e gen-class sono simili in quanto entrambi definiscono una classe denominata per la compilazione anticipata. La classe Gen è arrivata prima, seguita da deftype in clojure 1.2. Deftype è preferito e ha caratteristiche di prestazione migliori, ma è più restrittivo. Una classe deftype può essere conforme a un'interfaccia, ma non può ereditare da un'altra classe.

Reify e proxy vengono entrambi utilizzati per creare dinamicamente un'istanza di una classe anonima in fase di esecuzione. Il proxy è arrivato prima, reify è arrivato con deftype e defrecord in clojure 1.2. Reify è preferito, proprio come deftype, dove la semantica non è troppo restrittiva.

Ciò lascia la domanda sul perché sia ​​deftype che defrecord, poiché sono apparsi contemporaneamente e hanno un ruolo simile. Per la maggior parte degli scopi, vorremo utilizzare defrecord: ha tutte le varie bontà di clojure che conosciamo e amiamo, sequability e così via. Deftype è concepito per essere utilizzato come blocco predefinito di basso livello per l'implementazione di altre strutture di dati. Non include le normali interfacce clojure, ma ha l'opzione di campi modificabili (sebbene questa non sia l'impostazione predefinita).

Per ulteriori letture controlla:

La pagina dei tipi di dati di clojure.org

Il thread del gruppo Google in cui sono stati introdotti deftype e reify


1
Il thread del gruppo Google è stato molto prezioso. La mia comprensione è per il proxy java-interop, gen-class sono stati soppiantati principalmente da reify e deftype. Sono contento che ora abbiamo meno modi "consigliati" per definire i tipi.
Salil

2
@ Trylks: la capacità di trattare l'oggetto come una sequenza di coppie chiave-valore. Praticamente tutto ciò che è nativo di clojure può essere trattato come una sequenza, il che è molto potente.
Rob Lachlan

proxya volte è preferito perché consente la modifica dei metodi in fase di esecuzione. (ad es. The Joy of Clojure , 2a ed. suggerisce che questo potrebbe essere utile per modificare i callback in un gestore web.)
Marte

52

La risposta breve è che hanno tutti scopi diversi e utili. La complessità è dovuta alla necessità di interoperare efficacemente con le diverse caratteristiche della JVM sottostante.

Se non è necessaria alcuna interoperabilità Java, il 99% delle volte è meglio attenersi a defrecord o una semplice mappa Clojure.

  • Usa defrecord se vuoi usare i protocolli
  • Altrimenti una normale mappa Clojure è probabilmente la più semplice e comprensibile

Se le tue esigenze sono più complesse, il seguente diagramma di flusso è un ottimo strumento per spiegare perché dovresti scegliere una di queste opzioni rispetto alle altre:

http://cemerick.com/2011/07/05/flowchart-for-choosing-the-right-clojure-type-definition-form/

Diagramma di flusso per la scelta del modulo di definizione del tipo di chiusura corretto


1
grazie mille per il collegamento al diagramma di flusso. Aiuta il fatto che il blog sia del coautore di O'reilly's - Programming Clojure. Penso che questo processo decisionale sia piuttosto complesso. Le differenze tra l'interfaccia e la classe concreta o la necessità di definire metodi statici o meno o il tipo denominato o il tipo anonimo sono così vaste da richiedere un costrutto di linguaggio diverso?
Salil

4
le differenze non sono enormi, ma sono filosoficamente diverse in termini di ciò che stai cercando di ottenere. Penso che i molteplici approcci in Clojure riflettano queste differenze sottostanti, che è una buona ragione per cui dovrebbero essere assegnati nomi diversi.
mikera

Il diagramma di flusso è ottimo, ma non copre tutte le possibilità o le ragioni per utilizzare l'una o l'altra opzione o le combinazioni di esse. Nessun semplice grafico potrebbe.
Marte
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.