2009-12-01 11 views
11

Googles neue Sprache Go versucht, Abhängigkeiten Management durch explicitly requiring that all dependencies listed in a module actually be used zu erleichtern. Der Compiler weist ein Modul zurück, das eine Abhängigkeit zu einem Modul deklariert, ohne etwas aus diesem Modul zu verwenden.Pro und Kontra von Go, das ungenutzte Abhängigkeiten zurückweist

Es ist illegal, dass ein Paket sich selbst importiert oder ein Paket importiert, ohne auf einen der exportierten Bezeichner zu verweisen.

Ich kann mir einige offensichtliche Vorteile vorstellen (z. B. sauberere Module), aber vielleicht gibt es einige nicht offensichtliche. Der einzige Nachteil, den ich mir vorstellen kann, ist ein zu pedantischer Compiler, der sich beim Refactoring zu sehr beschwert, aber vielleicht gibt es noch mehr?

Haben Sie Erfahrungen mit anderen Sprachen, die dies erzwingen? Was sind die Vor- und Nachteile dieses Ansatzes?

Antwort

5

Nicht nur müssen Sie explizit alle Abhängigkeiten verwenden, sondern auch alle Variablen müssen verwendet werden. Der Compiler wird Ihnen Fehler geben, wenn Sie nicht verwendete Variablen haben.

Sie sind nervig. Aber es wird andere glücklich machen, weil sie sauberen Code bekommen.

Ich denke, dass Go Designer wahrscheinlich eine Sprache, die weitgehend IDE-abhängig ist.

+2

+1 für das IDE-basierte Design. Ich bin zu der gleichen Schlussfolgerung gelangt, hauptsächlich aufgrund der Tatsache, dass nur die Objektdateien etwas haben, das einer Kopfzeile ähnelt, und dass Go auch Module zum Analysieren von Go enthält. –

0

Wie von Yuku erwähnt, wenn Sie eine IDE haben, die auf Augenhöhe mit dem ist, was Netbeans und Eclipse für Java tun können, müssen Sie sich nicht wirklich um solche Dinge kümmern.

Klicken Sie mit der rechten Maustaste auf die kleine Glühbirne am Rand und wählen Sie "Alle nicht verwendeten Abhängigkeiten entfernen" aus.

Für Variablen, die nicht verwendet werden, erhalten sie normalerweise eine verzerrte Unterstreichung und sind ziemlich einfach zu erkennen.

Der einzige Unterschied hier ist, dass Sie im Gegensatz zu anderen Sprachen tatsächlich den Compiler beschweren zusätzlich zur IDE, aber wenn Sie eine IDE trotzdem verwenden, wird dies zu einem Nicht-Problem.

Bei der Arbeit haben wir Kodierungsrichtlinien, die ziemlich genau sagen, dass wir (natürlich) dasselbe für andere Sprachen tun müssen. Also würde ich sagen, dass diese Art von tatsächlich tatsächlich Anwendungen hat. Obwohl IMHO, sollte der Compiler dem Entwickler die Option geben, dieses Verhalten ein- und auszuschalten. Strenger Modus jemand?

+0

+1 für strikten Modus - Ich mag die Funktion, aber ich denke auch, es ist eine gute Idee, um es auszuschalten. –

1

Ich vermute, dass die größte Motivation für dieses und das größte Ergebnis eine Verbesserung der Kompilierzeiten ist. Das Tech-Vorschau-Video machte einen wichtigen Punkt in ihrer Fähigkeit, große Mengen an Code in kurzen Zeiträumen zu kompilieren (ihr Beispiel war 200.000 Zeilen Code in 8 Sekunden auf einem MacBook - keine Maschinenspezifikationen angegeben).

Auch im Tech-Video erwähnen sie ausdrücklich, dass eine der größten Möglichkeiten, die sie erreicht haben, darin bestand, die Art und Weise zu ändern, wie Module kompiliert und verknüpft wurden.

Hier ist ein Beispiel dafür, wie etwas in einem aktuellen C arbeiten würde/C++ System:

Klasse A wird in Header-Datei C_H definiert und in C_CPP umgesetzt. Klasse B stammt von C und ist in den Dateien B_H und B_CPP implementiert. Klasse A stammt von B und ist in den Dateien A_H und A_CPP implementiert.

Wegen der Ableitungsketten enthält A_CPP A_H, B_H und C_H. B_CPP umfasst B_H und C_H. C_CPP enthält C_H. Aufgrund der Natur des C-Präprozessors, der im Wesentlichen ein #include in eine Ausschneide- und Einfügeoperation umwandelt, werden die Inhalte von C_H dreimal durch den Compiler durchlaufen und B_H wird zweimal durchlaufen.

Ferner werden die Inhalte von A_CPP, B_CPP und C_CPP alle leben in ihrem eigenen Objektdateien. Daher, wenn der Linker A.o auflösen will, ist er gezwungen, sowohl B.o als auch C.o. Auch wenn es B.o auflöst, muss es C.o erneut verarbeiten.

Vorkompilierte Header können ziemlich viel mit dem ersten Teil dieses Problems helfen, aber sie können auch eine royal Schmerzen zu pflegen sein und ich kenne eine Menge Entwickler, die sie einfach aus diesem Grund nicht verwenden. Es ändert auch nicht grundlegend das Problem - die Header werden noch mehrfach auf mehreren Ebenen verarbeitet, nur dass jetzt eine vorkompilierte Binärdatei anstelle der Quelle verarbeitet wird. Mehrere Schritte sind ausgeschnitten, aber nicht der gesamte Prozess.

Go nähert sich die Dinge anders. Mit den Worten gerade aus den PDF from their tech talk:

„The Go-Compiler zieht transitiv Abhängigkeitstyp Info vom Objekt Datei - aber nur, was er braucht Wenn A.go auf B.go hängt, hängt von C. .go: - kompilieren C.go, B.go, dann A.go. - kompilieren A.go, Compiler liest Bo nicht Co in großem Umfang, diese Speedup ein sehr groß sein kann.“

OK, leichte Tangente ist fertig. Warum ist das relevant? Die Antwort ist auch in der Go Tech Talk PDF:

"Package-Modell: Explizite Abhängigkeiten , um schnellere Builds zu ermöglichen."

Ich vermute, dass der Go-Entwickler die Haltung nahm, dass bei der Kompilierung Zeiten in Sekunden gemessen werden, auch für sehr große Projekte, dass es, dass die Abkürzung für Entwickler zu halten Kompilierungszeiten produktiver ist. Sagen wir, ich brauche 8 Sekunden, um 200.000 Codezeilen zu kompilieren und zu entdecken, dass ich einen überflüssigen Paketimport habe, 5-10 Sekunden (mit einer guten IDE oder guter Vertrautheit mit deiner Entwicklungsumgebung), um ihn zu finden und zu beheben, und weitere 8 Sekunden zum Neukompilieren. Nenne es insgesamt 30 Sekunden - und jetzt bleiben alle meine zukünftigen Compiles im Bereich von 10 Sekunden. Oder wir können unser Modul wachsen lassen, indem wir unnötige Abhängigkeiten mit einbeziehen und beobachten, dass die Kompilierzeit von 8 auf 10, 12 oder 15 Sekunden steigt. Es scheint nicht viel zu sein, weil wir alle daran gewöhnt sind, Zeiten in der Größenordnung von Minuten zu kompilieren - aber wenn man anfängt zu erkennen, dass das eine 25% ige Leistungsverschlechterung ist, hört man auf und denkt eine Minute darüber nach.

Go kompilieren Zeiten sind schon blitzschnell. Berücksichtigen Sie auch, dass die Prozessorgeschwindigkeiten immer noch ansteigen (wenn auch nicht so stark wie in der Vergangenheit) und dass auch die Anzahl der verfügbaren Kerne zunimmt (und das Kompilieren großer Mengen an Code gut für Multithreading geeignet ist). 200.000 Zeilen Code in 8 Sekunden heute bedeutet, dass es nicht unvernünftig ist, sich 200.000 Codezeilen vorzustellen, die im Wesentlichen sofort in 10 Jahren kompiliert werden. Ich denke, das Go-Team hier eine bewusste Entscheidung getroffen hat, zu kompilieren mal eine Sache der Vergangenheit zu machen, und während die Ausgabe, die Sie bis bringen nur ein sehr kleiner Teil davon ist, es ist noch ein Teil davon.

Ganz anders scheint auch das Go-Team eine Philosophie des Sprachdesigns entwickelt zu haben, die einige gute Programmierpraktiken erfordert.Zu ihrer Ehre haben sie sich bemüht, das ohne ernsthafte Leistungseinbußen zu erreichen und weitgehend gelungen. [Nebenbei bemerkt: Die einzigen beiden Dinge, die ich mir vorstellen kann, sind die Garbage Collection und gewaltsam initialisierte Variablen - und letzteres ist heutzutage ziemlich trivial.] Dies wird einige Programmierer irritieren, während es andere glücklich macht . Es ist ein altes, altes Argument in der Programmierwelt, und es ist ziemlich klar, auf welcher Seite Go steht, ob es ihm gefällt oder nicht.

Ich denke, dass die beiden Kräfte zusammen ihre Entscheidung beeinflusst haben, und ich denke, dass es am Ende des Tages ein guter Weg ist, obwohl ich andere Kommentatoren unterstütze, die vorgeschlagen haben, eine "-" Flagge zuzulassen Dies macht dieses spezielle Verhalten insbesondere in den frühen Phasen eines Projektlebenszyklus optional. Ich könnte mir leicht vorstellen, Variablen zu definieren oder Pakete zu integrieren, wenn ich anfange, Code zu schreiben, von dem ich weiß, dass ich ihn später brauche, obwohl ich den Code, der sie benötigt, noch nicht geschrieben habe.

+0

"Wenn Modul A das Modul B erfordert, das Modul C erfordert, kompilieren die meisten Compiler C, kompilieren B und C (erneut) und kompilieren dann A, B (wieder) und C (erneut) und dann aussortieren Probleme" - Nein würden sie nicht. Sie kompilieren jede Quelldatei einmal und verknüpfen sie dann miteinander. –

+0

Nick, ich habe mich etwas falsch geäußert und werde meine Antwort momentan mit der Korrektur aktualisieren. Wenn Sie Header-Dateien in C/C++ verwenden, erhalten Sie jedoch ** große ** Codeabschnitte, die mehr als einmal kompiliert werden. –

+0

Ja, Header werden mehr als einmal eingeschlossen, da sie vom Präprozessor verarbeitet werden. Wenn Sie in Ihren Header-Dateien "große" Teile des Codes haben, UR DOIN IT WRONG. –