Commenti di tipo chiarimento e controllo del tipo nelle lingue dinamiche

5

Spesso sento che c'è qualcosa di sbagliato quando codice blocchi come:

function foo (arg){ // arg: a SomeClass object
    ...
}

o

function foo (arg){
    if (Object.prototype.toString.apply(arg) !== '[object Array]')
        throw new Error("Parameter must be an array");
    ...
}

. Con un linguaggio tipizzato staticamente non dovrei né chiarire il tipo di argomento previsto né verificare la conformità a questa aspettativa. Inoltre, la possibilità di specificare un tipo di reso rende il codice ancora più descrittivo.

OTOH alcuni casi si prestano al codice di auto-documentazione:

function parse (json){
    ...
}

. Nell'esempio sopra, è abbastanza ragionevole supporre che i tuoi utenti API sapranno sia cosa dovrebbe fare la funzione, sia quali valori degli argomenti saranno accettabili.

Tuttavia altre volte chiarendo l'intento del codice scegliendo nomi "chiarificanti" si otterrebbero nomi lunghi e scomodi che mischiano il tipo atteso di una variabile e il suo ruolo .

Sto utilizzando linguaggi dinamici con una mentalità sbagliata?

Quali convenzioni, tecniche, modelli possono salvarne uno dal dover scrivere brutti codici di controllo del tipo e / o eccessivamente a seconda dei commenti?

    
posta vemv 13.10.2011 - 17:01
fonte

5 risposte

2

Ecco la cosa.

Normalmente le lingue tipizzate staticamente hanno un compilatore, e il compilatore digita il controllo per prevenire una certa classe di bug al momento della compilazione - cioè, se hai uno di quei bug nel tuo codice, non avrai nemmeno la possibilità di incontrarlo in produzione, perché non avrai nulla da eseguire finché non correggi il bug. Questo è probabilmente il più grande vantaggio della digitazione statica.

I linguaggi dinamici (spesso) non hanno un compilatore e, di conseguenza, qualsiasi tipo di controllo che potresti voler fare accade in fase di esecuzione e se i tuoi tipi non funzionano nel modo previsto, puoi solo scoprire attraverso test. Ma indovina un po ', se non controlli affatto, puoi anche trovare bug attraverso i test. Il valore aggiunto del controllo del tipo, quindi, è zero.

Il modo usuale per andare su queste cose è catturato nel mantra Python "più facile chiedere perdono che permesso" - invece di controllare i tipi dei tuoi argomenti, si presuppone che siano corretti, e quando ciò causa problemi, si cattura l'eccezione e recuperare.

L'idea della digitazione anatra è strettamente correlata: non mi interessa il tuo tipo, purché tu implementi i metodi che mi servono.

Ci sono due aspetti negativi dell'approccio dinamico di cui devi essere consapevole: gli effetti collaterali (quando chiedi perdono, devi anche ripulire tutti gli effetti collaterali che hai causato fino ad ora) e gli scontri di denominazione accidentale ( data.save("example.txt") è concettualmente diverso da rescueBoat.save(swimmer) )

    
risposta data 13.10.2011 - 17:26
fonte
7

Am I using dynamic languages with the wrong mindset?

Penso di sì, sì. Preoccupati meno di che tipo è e di più su quale funzionalità fornisce.

Di solito è possibile controllarlo esplicitamente al runtime. Ad esempio, in Ruby, puoi chiamare respond_to su qualsiasi oggetto e scoprire se è in grado di rispondere ai metodi che intendi chiamare. Oppure puoi semplicemente chiamare il metodo e fallirà se non può gestirlo.

Questo è noto come digitazione anatra, se vuoi cercare ulteriori informazioni.

    
risposta data 13.10.2011 - 17:25
fonte
3

Se l'argomento è 'a Duck', e '.quack (); è come un Duck e it' .walk () è come un Duck, quindi dice che è di tipo 'Duck' ... potrebbe essere ridondante e fuorviante, in quanto potrebbero esserci anche altre classi completamente estranee a Duck che anche ".quack ();" come un Anatra e '.walk ()' come un Anatra.

I nomi significativi e i test di regressione automatizzati possono essere molto utili.

Se qualcuno chiama il tuo metodo con qualcosa di molto non-anatra e non funziona nel modo in cui si aspettano, allora sicuramente i loro test falliranno. E possono imparare a fare qualcosa di più appropriato ai loro bisogni.

Quindi: scrivi un buon codice. E non preoccuparti troppo. ; - >

    
risposta data 13.10.2011 - 17:24
fonte
2

Penso che la tua mentalità sia fondamentalmente solida, purché non trascuri i vantaggi che un linguaggio dinamico ti offre tra cui la riduzione del boilerplate, la capacità di gestire i disadattamenti di impedenza come l'accesso al database e l'espressività localizzata.

Un piccolo suggerimento è di incapsulare il controllo del tipo di runtime sotto forma di asserzione. Questo rende ovvio il ruolo del codice di controllo ed è efficace se usato insieme ai test di unità.

Tuttavia, le dichiarazioni di tipo statico non forniscono solo i mezzi per un compilatore per eseguire un insieme di base di test unitari obbligatori, forniscono molte informazioni al codificatore sugli oggetti che stanno usando e sui metodi che stanno chiamando. Inoltre, fornire le asserzioni e i test per compensare l'assenza del controllo di tipo di un compilatore richiede sforzo, ripetuto più e più volte. Preferirei avere una singola parola chiave per indicare un tipo rispetto a molte righe di asserzioni e test.

Sebbene i linguaggi dinamici possano essere molto espressivi a livello locale, ad esempio all'interno di una funzione, sono molto meno efficaci nel mostrare le relazioni tra i componenti in una base di codice estesa. Preferirei esaminare i dettagli e le relazioni tra gli oggetti rivelati dal codice in un insieme di dichiarazioni di classe piuttosto che esaminare un mucchio di codice di produzione procedurale e test unitari che potrebbero essere o non essere completi.

Recentemente ho mantenuto un codice JavaScript non familiare che implicava la manipolazione di un albero basato su alcuni JSON caricati da un server. Non avevo idea di cosa fosse garantito o addirittura previsto per un dato nodo nell'albero. Una dichiarazione di classe avrebbe almeno dato allo sviluppatore originale da qualche parte il compito di appendere informazioni sulle aspettative sui vari nodi.

Mentre preferisco scrivere in un linguaggio dinamico, di certo preferisco leggere e mantenere il codice in una tipizzazione statica.

    
risposta data 14.10.2011 - 08:54
fonte
1

La mia esperienza generale è che il 90% delle volte il nome del ruolo implica il tipo. Per esempio. potresti avere User class apparire come "creatore", "proprietario", "editor" e semplicemente "currentUser" più e più volte in una data applicazione. Se si utilizzano tali identificatori per i ruoli in modo coerente e si presta un po 'di attenzione per evitare di nominare i ruoli di tipi diversi in modo simile (ad esempio, non utilizzare "proprietario" per gli oggetti padre se lo si è utilizzato per il documento proprietario dell'utente), chiunque usi l'interfaccia imparerà che tipo di oggetti dovrebbero andare dove abbastanza veloce.

Gran parte del resto sarà ovvia dal contesto, specialmente se si definiscono anche azioni coerenti. L'uso di nomi lunghi o semplicemente l'accettazione del nome non è descrittivo e l'aggiunta di una documentazione sufficiente dovrebbe essere sufficiente per i pochi casi che rimangono.

    
risposta data 14.10.2011 - 12:14
fonte

Leggi altre domande sui tag