2009-12-01 10 views
11

La nuova lingua di Google Go cerca di semplificare la gestione delle dipendenze tramite explicitly requiring that all dependencies listed in a module actually be used. Il compilatore rifiuterà un modulo che dichiara una dipendenza da un modulo senza utilizzare nulla da quel modulo.Pro e contro di Go che rifiuta le dipendenze inutilizzate

È illegale per un pacchetto importare se stesso o importare un pacchetto senza fare riferimento a nessuno dei suoi identificatori esportati.

Posso pensare ad alcuni ovvi vantaggi (ad esempio, moduli più puliti) ma forse ce ne sono alcuni non ovvi. L'unico svantaggio che posso pensare è avere un compilatore eccessivamente pedante, lamentarsi troppo durante il refactoring, ma forse ce ne sono altri?

Avete esperienza con altri linguaggi che fanno rispettare questo? Quali sono i pro e i contro di questo approccio?

risposta

5

Non solo è necessario utilizzare in modo esplicito tutte le dipendenze, ma anche tutte le variabili devono essere utilizzate. Il compilatore ti darà errori quando hai variabili inutilizzate.

Sono fastidiosi. Ma renderà felici gli altri perché ottengono il codice pulito.

Sto pensando che probabilmente i progettisti Go intendevano essere un linguaggio largamente dipendente dall'IDE.

+2

+1 per la progettazione basata su IDE. Ho raggiunto la stessa conclusione, in gran parte dal fatto che solo i file oggetto hanno qualcosa che assomiglia a un'intestazione, e anche che Go include moduli per l'analisi di Go. –

0

Come menzionato da yuku, se hai un IDE che è alla pari con quello che Netbeans ed Eclipse possono fare per java, non devi preoccuparti di questo genere di cose.

Fare clic con il pulsante destro del mouse sulla piccola lampadina sul margine e selezionare "Rimuovi tutte le dipendenze non utilizzate".

Per le variabili che non vengono utilizzate, di solito presentano una sottolineatura ondulata e sono piuttosto facili da individuare.

L'unica differenza è che a differenza di altri linguaggi, si ha in realtà il compilatore lamentarsi oltre alla IDE, ma se si utilizza un IDE in ogni caso, questo diventa un non-problema.

Al lavoro abbiamo politiche di codifica che affermano praticamente che dobbiamo fare la stessa cosa (noi stessi), tra le altre cose, naturalmente per altre lingue. Quindi direi che questo genere di cose ha effettivamente applicazioni reali. Sebbene IMHO, il compilatore dovrebbe dare allo sviluppatore la possibilità di attivare e disattivare questo comportamento. Modalità rigorosa chiunque?

+0

+1 per la modalità rigorosa: mi piace la funzione, ma penso anche che sia una buona idea essere in grado di disattivarla. –

1

Sto indovinando che la più grande motivazione per questo, e il risultato più grande, è un miglioramento dei tempi di compilazione. Il video di anteprima tecnica ha rappresentato un punto importante della loro capacità di compilare grandi quantità di codice in periodi di tempo brevi (il loro esempio era 200.000 righe di codice in 8 secondi su un MacBook - non sono state fornite le specifiche della macchina).

Anche nel video tecnico, menzionano specificamente che uno dei più grandi modi che hanno ottenuto è stato quello di cambiare il modo in cui i moduli sono stati compilati e collegati.

Ecco un esempio di come qualcosa sarebbe lavorare in una corrente C/++ sistema C:

Classe A è definita nel file di intestazione C_H e attuata C_CPP. La classe B deriva da C ed è implementata nei file B_H e B_CPP. La classe A deriva da B ed è implementata nei file A_H e A_CPP.

A causa delle catene di derivazione, A_CPP include A_H, B_H e C_H. B_CPP include B_H e C_H. C_CPP include C_H. A causa della natura del preprocessore C, che trasforma essenzialmente un #include in un'operazione di copia e incolla, il contenuto di C_H viene eseguito attraverso il compilatore 3 volte e B_H viene eseguito due volte.

Inoltre, i contenuti di A_CPP, B_CPP e C_CPP vivono tutti nei propri file oggetto. Quindi quando il linker va a risolvere A.o, è obbligato a caricare ed elaborare sia B.o che C.o. Inoltre, quando risolve B.o, deve elaborare nuovamente C.o.

Le intestazioni precompilate possono aiutare un bel po 'con la prima parte di questo problema, ma possono anche essere un problema reale da mantenere e conosco molti sviluppatori che semplicemente non li usano per questo motivo. Inoltre, non cambia radicalmente il problema: le intestazioni vengono ancora elaborate a più livelli più volte, solo ora viene elaborato un binario precompilato al posto dell'origine. Sono stati tagliati diversi passaggi, ma non l'intero processo.

Go si avvicina alle cose in modo diverso. Nelle parole dritto fuori dalla PDF from their tech talk:

"Il compilatore Go tira transitiva dipendenza tipo di informazioni dal file oggetto - ma solo ciò di cui ha bisogno Se A.go dipende B.go dipende C. .go: - Compila C.go, B.go, quindi A.go. - per compilare A.go, il compilatore legge Bo not Co In scala, questo può essere un enorme aumento di velocità ".

OK, viene eseguita una leggera tangente. Perché è rilevante? La risposta è anche nel Go Tech Talk PDF:

"Modello di pacchetto: dipendenze esplicite per abilitare build più veloci."

Sto indovinando che gli sviluppatori Go hanno preso la posizione che quando i tempi di compilazione sono misurati in secondi, anche per progetti molto grandi, che è più produttivo per gli sviluppatori di mantenere tempi di compilazione quel breve. Supponiamo che mi occorrono 8 secondi per compilare 200.000 righe di codice e scoprire che ho importato un pacchetto estraneo, 5-10 secondi (con un buon IDE o una buona familiarità con l'ambiente di sviluppo) per trovarlo e risolverlo, e altri 8 secondi da ricompilare. Chiamalo per 30 secondi in totale - e ora tutte le mie future compilazioni rimangono nella gamma dei 10 secondi. Oppure possiamo far crescere il nostro modulo includendo dipendenze non necessarie e osservando che il tempo di compilazione sale da 8 a 10, 12 o 15 secondi. Non sembra molto perché siamo tutti abituati a compilare i tempi nell'ordine dei minuti - ma quando inizi a capire che si tratta di un degrado delle prestazioni del 25%, ti fermi a pensarci per un minuto.

I tempi di compilazione sono già velocissimi. Si consideri inoltre che le velocità del processore sono ancora in aumento (se non così tanto come in passato) e che il numero di core disponibili è in aumento (e la compilazione di grandi quantità di codice è adatta al multithreading). 200.000 righe di codice in 8 secondi oggi significano che non è irragionevole immaginare 200.000 righe di codice che compili essenzialmente istantaneamente in 10 anni. Penso che il team di Go abbia preso una decisione consapevole qui per rendere i tempi di compilazione una cosa del passato, e mentre il problema che si presenta è solo una piccola parte di questo, lo è ancora una parte di quello.

Su un'altra nota, il team di Go sembra aver sviluppato una filosofia di progettazione linguistica che costringe alcune buone pratiche di programmazione.A loro merito, hanno fatto lo sforzo per ottenerlo senza gravi penalizzazioni delle prestazioni, e in gran parte riuscite. [A parte: le uniche due cose a cui posso pensare che influiscono negativamente sulle prestazioni sono la garbage collection e le variabili inizializzate forzatamente - e quest'ultima è piuttosto banale in questo giorno ed età.] Questo farà arrossire timidamente alcuni programmatori, mentre rende felici gli altri . È una vecchia, vecchia argomentazione nel mondo della programmazione, ed è abbastanza chiaro da che parte Go è venuto giù, che ti piaccia o no.

Penso che le due forze abbiano influenzato la loro decisione, e penso che alla fine è un buon modo per andare, anche se sostengo altri commentatori qui che hanno suggerito di permettere una bandiera "--strict" o alcuni tale da rendere facoltativo questo particolare comportamento, in particolare durante le prime fasi del ciclo di vita di un progetto. Potrei facilmente vedermi definire variabili o includere pacchetti quando inizierò a scrivere codice che so di aver bisogno in seguito, anche se non ho ancora scritto il codice che ne ha bisogno.

+0

"Se il modulo A richiede il modulo B che richiede il modulo C, molti compilatori compilano C, compilano B e C (di nuovo), quindi compilano A, B (di nuovo) e C (di nuovo) e risolvono i problemi di collegamento" - no, non lo farebbero. Compilano ogni file sorgente una volta, quindi li collegano insieme. –

+0

Nick, ho riportato in modo errato e aggiornerò momentaneamente la mia risposta con la correzione. Tuttavia, se si utilizzano i file di intestazione in C/C++, si finisce con ** grandi ** porzioni di codice che vengono compilate più di una volta. –

+0

Sì, le intestazioni vengono incluse più volte, perché vengono gestite dal preprocessore. Se si hanno 'grandi' bit del codice nei file di intestazione, UR DOIN IT WRONG. –