2012-10-17 4 views
5

Utilizzo una libreria di terze parti (clj-msgpack) e desidero estendere un protocollo per un tipo per il quale la libreria fornisce anche un gestore.Estensione di un protocollo fornito da libreria senza impatto sugli altri utenti

Di per sé, è abbastanza semplice, ma esiste un modo per farlo che non influenzi gli altri utenti di questa libreria in esecuzione nella stessa JVM? Qualcosa di simile a un vincolo di una variabile dinamica (che ha effetto solo sotto un determinato punto della pila) sarebbe l'ideale.

Allo stato attuale, sto eseguendo un override incondizionato ma utilizzando una variabile dinamica per abilitare il mio comportamento modificato; tuttavia, questo mi sembra troppo simile al patch delle scimmie per il mio comfort.

Per i curiosi, il (abominio ammesso) Sto mettendo a posto segue:

(in-ns 'clj-msgpack.core) 

(def ^:dynamic *keywordize-strings* 
    "Assume that any string starting with a colon should be unpacked to a keyword" 
    false) 

(extend-protocol Unwrapable 
    RawValue 
    (unwrap [o] 
    (let [v (.getString o)] 
     (if (and *keywordize-strings* (.startsWith v ":")) 
     (keyword (.substring v 1)) 
     v)))) 
+0

Forcella, aggiungere la funzionalità è necessario, e invia una richiesta di pull; ^) – noahlz

+0

@noahz Ho inviato un ticket con il codice. Anche se a monte questa caratteristica è interessante, è una cosa molto discutibile, ma non sono sicuro che lo accetterei se fossi in loro. –

+0

Ho fatto quel commento tounge-cheek (per i motivi che hai menzionato), ma d'altra parte ... le API dovrebbero essere "aperte per l'estensione, chiuse per la modifica". – noahlz

risposta

1

dopo aver riflettuto Vedo due approches di base (uno dei quali ricevo da voi):

Binding dinamico (come lo state facendo ora):

Alcuni lamentano che il binding dinamico vale per il principal di più supprise; "cosa? si comporta in questo modo solo quando viene chiamato da lì?". Anche se personalmente non ritengo che questa sia una cosa brutta (tm), alcune persone lo fanno. In questo caso corrisponde esattamente al tuo desiderio e finché hai un punto in cui decidi se vuoi stringhe con parole chiave, questo dovrebbe funzionare. Se aggiungi un secondo punto che li modifica indietro e un percorso di codice che attraversa i due pozzetti ... il tuo da solo. Ma hey, il codice di lavoro ha i suoi meriti.

Ereditarietà:

stile good'ol java o utilizzando gerarchie add-hoc di Clojure si potrebbe estendere il tipo di oggetto che si sta passando in giro per essere keywordized-string-widgewhatzit che si estende widgewhatzit e aggiungere un nuovo gestore per la sottoclasse specifica. Questo funziona solo in alcuni casi e forza un diverso stile di oggetto sul resto del disegno. Alcune persone intelligenti sostengono anche che segue ancora il principio della sorpresa più grande perché il tipo di oggetti sarà diverso quando viene chiamato tramite un altro percorso di codice.


Personalmente vorrei andare con la soluzione esistente a meno che non si può cambiare tutto il tuo programma di utilizzare le parole chiave, invece di stringhe (che naturalmente la mia prima (potenzialmente controversa) a scelta)

+0

Non riesco a fare l'approccio di implementazione del protocollo basato su sottoclassi perché l'oggetto che viene gestito è generato dalla libreria stessa (in realtà, da una libreria _it_ usa). Questo sarebbe di gran lunga la mia preferenza altrimenti, in quanto è completamente a mani libere rispetto ad altri utenti. –

+0

... a proposito, il motivo principale per cui non mi piace l'approccio attuale è che modifica il codice della libreria. Sì, il nuovo comportamento dovrebbe essere attivato da un binding dinamico ... ma se upstream modifica il codepath originale e io non adotto quella funzionalità nella mia versione sovrascritta, tutti gli utenti della libreria all'interno dell'ambiente Clojure dato perdono l'upstream cambiare, non solo il mio codice. Sono stato abbastanza bruciato dalle patch delle scimmie nei mondi Ruby e Python per essere molto, molto diffidente nell'approvarlo qui. –

+0

Bene, ora che lo hai pubblicato qualcuno seguirà il tuo esempio ;-) Stai raggiungendo un'altra libreria e ne giri i bit, quindi è probabile che ci sia un limite alla pulizia di questo: -/ –

Problemi correlati