2012-04-23 14 views
18
  • defn = pubblico
  • defn- = privato

Forse ho un cattivo stile di codifica Clojure - ma trovo che la maggior parte delle funzioni scrivo in I Clojure sono piccole funzioni di supporto che non voglio esporre.Clojure, defn, defn-, pubblico/privato, il default

C'è qualche opzione di configurazione, dove:

  • defn = privati ​​per impostazione predefinita,
  • e di fare qualcosa di pubblico, che devo fare defn+?

Grazie!

risposta

16

No. Non c'è.

Un approccio alternativo che potrebbe o non potrebbe funzionare per voi è dichiarare uno spazio dei nomi foo.bar.internal contenente tutti gli helper privati ​​che viene utilizzato dallo spazio dei nomi foo.bar. Ciò presenta vantaggi rispetto alle dichiarazioni di funzioni private quando si desidera utilizzare funzioni private nelle espansioni di macro.

+12

Non solo che non c'è, sarebbe davvero pasticcio con la mente di ogni altro clojuriano che osserva tale codice. Lo scoraggerei anche se fosse fattibile. –

4

Se è probabile che le "funzioni di supporto" vengano utilizzate una sola volta, è possibile scegliere di renderle locali per le funzioni più grandi o di scriverle come funzioni anonime. Vedi letfn: http://clojuredocs.org/clojure_core/clojure.core/letfn e http://clojuredocs.org/clojure_core/clojure.core/fn.

Non uso quasi mai lo letfn.

+0

Non penso che le dimensioni di queste funzioni di supporto siano importanti. Se vengono utilizzati più di una volta, dovrebbero essere effettivamente estratti per il codice dell'essiccatore. Non riesco davvero a vedere un motivo per renderli locali/anonimi a meno che non vengano utilizzati solo una volta localmente. – tjb1982

+0

Questo è vero. Adatterò la risposta. –

+0

Ho provato a usare 'letfn' per i miei aiutanti, ma ha reso il mio codice troppo disordinato. Così, dopo poco tempo tornai a 'defn-'. –

4

Come affermato da @kotarak, non c'è modo (per quanto ne so) di farlo, né è auspicabile.

Ecco il motivo per cui non mi piace defn-:

ho scoperto che quando si usa varie librerie Clojure a volte bisogno di modificare leggermente una funzione per meglio soddisfare le mie esigenze particolari. Spesso è qualcosa di abbastanza piccolo, e questo ha senso solo nel mio caso particolare. Spesso questo è solo un char o due.

Ma quando questa funzione riutilizza le funzioni private interne, rende più difficile la modifica. Devo copiare e incollare tutte quelle funzioni private.

Capisco che questo è un modo per il programmatore di dire che "questo potrebbe cambiare senza preavviso".

Indipendentemente da ciò, vorrei che la convenzione opposta:

  • usano sempre defn, che rende tutto pubblico
  • uso defn+ (che non esiste ancora) per specificare al programmatore quali funzioni fanno parte di l'API pubblica che dovrebbe utilizzare. defn+ non dovrebbe essere diverso da defn in caso contrario.

Inoltre si ricorda che è possibile in ogni caso access private functions:

;; in namespace user 
user> (defn- secret [] 
     "TOP SECRET") 

;; from another namespace 
(#'user/secret) ;;=> "TOP SECRET" 
+2

Dalla mia esperienza con Ruby che consente l'accesso illimitato a tutto (basta usare # send per i metodi privati). Finisce per essere un immenso casino e gli sviluppatori meno esperti tendono ad abusare di questa "libertà" facendo cose veramente brutte. – yagooar

+0

Dopo aver lavorato su un grande codice di clojure, ho trovato un certo valore per il caso privato 'defn-'. Devo ancora provare a usare 'defn +'. – nha

+2

Esattamente. Se commetto un errore nel modificare la funzione di qualcun altro, è colpa mia. Come programmatore, impedirmi di modificare gli interni è un insulto. Tutto dovrebbe essere pubblico. Basta documentare correttamente eventuali problemi potenziali e non è necessario per privati. – Rebs

4

La bellezza di Clojure essere un Lisp, è che si può costruire e adattare la lingua in base alle proprie esigenze. Consiglio vivamente di leggere On Lisp, by Paul Graham. Ora libera il suo libro gratis.

Per quanto riguarda il tuo suggerimento di defn + vs defn vs defn-. Questo mi sembra un buon caso per scrivere la tua Macro. defn è una funzione e defn- è una macro. Puoi semplicemente ridefinirli come desideri o avvolgerli nel tuo.

Segue un suggerimento per l'implementazione, basato principalmente sull'implementazione di Clojure, inclusa una semplice utility e un test.

(defmacro defn+ 
    "same as Clojure's defn, yielding public def" 
    [name & decls] 
    (list* `defn (with-meta name (assoc (meta name) :public true)) decls)) 

(defmacro defn 
    "same as Clojure's defn-, yielding non-public def" 
    [name & decls] 
    (list* `defn (with-meta name (assoc (meta name) :private true)) decls)) 

(defn mac1 
    "same as `macroexpand-1`" 
    [form] 
    (. clojure.lang.Compiler (macroexpand1 form))) 

(let [ ex1 (mac1 '(defn f1 [] (println "Hello me."))) 
     ex2 (mac1 '(defn+ f2 [] (println "Hello World!"))) ] 
    (defn f1 [] (println "Hello me.")) 
    (defn+ f2 [] (println "Hello World!")) 
    (prn ex1) (prn (meta #'f1)) (f1) 
    (prn ex2) (prn (meta #'f2)) (f2)) 
Problemi correlati