2009-12-01 4 views
11

La nouvelle langue de Google Go tente de faciliter la gestion des dépendances par explicitly requiring that all dependencies listed in a module actually be used. Le compilateur rejettera un module qui déclare une dépendance à un module sans utiliser quoi que ce soit de ce module.Avantages et inconvénients de Go rejetant les dépendances non utilisées

Il est illégal pour un paquet d'importer lui-même ou d'importer un paquet sans faire référence à l'un de ses identifiants exportés.

Je peux penser à certains avantages évidents (par exemple des modules de nettoyage) mais peut-être il y en a certains qui ne sont pas évidents. Le seul inconvénient que je peux penser est d'avoir un compilateur trop pédant, se plaignant trop lors du refactoring, mais peut-être qu'il y en a plus?

Avez-vous de l'expérience dans d'autres langues? Quels sont les avantages et les inconvénients de cette approche?

Répondre

5

Non seulement vous devez utiliser explicitement toutes les dépendances, mais toutes les variables doivent également être utilisées. Le compilateur vous donnera des erreurs lorsque vous avez des variables inutilisées.

Ils sont agaçants. Mais cela rendra les autres heureux parce qu'ils auront du code propre.

Je pense que les concepteurs de Go vont probablement être un langage largement dépendant de l'IDE.

+2

+1 pour la conception basée sur l'IDE. Je suis arrivé à la même conclusion, en grande partie du fait que seuls les fichiers objets ont quelque chose qui ressemble à un en-tête, et que Go inclut des modules pour l'analyse de Go. –

0

Comme mentionné par yuku, si vous avez un IDE qui est à la hauteur de ce que Netbeans et Eclipse peuvent faire pour Java, vous n'avez pas vraiment à vous soucier de ce genre de chose.

Faites un clic droit sur la petite ampoule dans la marge et sélectionnez "Supprimer toutes les dépendances inutilisées".

Pour les variables qui ne sont pas utilisées, elles sont généralement soulignées de façon irrégulière et sont assez faciles à repérer. La seule différence ici est que contrairement aux autres langages, le compilateur se plaint en plus de l'IDE mais si vous utilisez un IDE de toute façon, cela ne pose aucun problème. Au travail, nous avons des politiques de codage qui stipulent à peu près que nous devons faire la même chose (nous-mêmes), entre autres choses, pour d'autres langues, bien sûr. Donc je dirais que ce genre de choses a effectivement de vraies applications. Bien qu'à mon humble avis, le compilateur devrait donner au développeur la possibilité de basculer ce comportement sur et en dehors. Strict mode quelqu'un?

+0

+1 pour le mode strict - J'aime la fonctionnalité, mais je pense aussi que c'est une bonne idée de pouvoir l'éteindre. –

1

Je suppose que la plus grande motivation pour cela, et le plus grand résultat, est une amélioration des temps de compilation. La vidéo de prévisualisation de technologie a fait un point important de leur capacité à compiler de grandes quantités de code dans de courtes périodes de temps (leur exemple était 200 000 lignes de code en 8 secondes sur un MacBook - aucune spécification de machine donnée).

Également dans la vidéo technique, ils mentionnent spécifiquement que l'un des moyens les plus importants qu'ils ont réussi à faire était de changer la façon dont les modules ont été compilés et liés.

Voici un exemple de la façon dont quelque chose fonctionnerait dans un système C/C++ actuel:

classe A est définie dans le fichier d'en-tête C_h et mis en œuvre C_CPP. La classe B dérive de C et est implémentée dans les fichiers B_H et B_CPP. La classe A dérive de B et est implémentée dans les fichiers A_H et A_CPP.A cause des chaînes de dérivation, A_CPP inclut A_H, B_H et C_H. B_CPP inclut B_H et C_H. C_CPP inclut C_H. En raison de la nature du préprocesseur C, qui transforme essentiellement un #include en une opération de couper-coller, le contenu de C_H est exécuté trois fois dans le compilateur et B_H est exécuté deux fois.

En outre, les contenus de A_CPP, B_CPP et C_CPP résident tous dans leurs propres fichiers objets. Par conséquent, lorsque le lieur va résoudre A.o, il est forcé de charger et de traiter à la fois B.o et C.o. En outre, lorsqu'il résout B.o, il doit à nouveau traiter C.o.

Les en-têtes précompilés peuvent aider un peu avec la première partie de ce problème, mais ils peuvent également être une douleur royale à maintenir et je connais beaucoup de développeurs qui ne les utilisent tout simplement pas pour cette raison. Cela ne change pas non plus fondamentalement le problème - les en-têtes sont encore traités à plusieurs niveaux plusieurs fois, seulement maintenant un binaire précompilé est traité au lieu de la source. Plusieurs étapes sont coupées, mais pas tout le processus.

Go approche les choses différemment. Pour reprendre les mots tout droit sorti de la PDF from their tech talk:

« Le compilateur Go tractions transitif info type de dépendance à partir du fichier objet - mais seulement ce dont il a besoin Si A.go dépend de B.go dépend C. .go: - compiler C.go, B.go, puis A.go - pour compiler A.go, compilateur lit Bo pas Co À l'échelle, cela peut être une accélération énorme. "

OK, une légère tangente est effectuée. Pourquoi est-ce pertinent? La réponse est également dans le Go Tech Talk PDF:

"Modèle de package: dépendances explicites pour permettre des générations plus rapides."

Je devine que les développeurs Go ont pris la position que lorsque les temps sont mesurés en Compile secondes, même pour les très grands projets, qu'il est plus productif pour les développeurs de garder que les temps de compilation court. Dites qu'il me faut 8 secondes pour compiler 200 000 lignes de code et découvrir que j'ai une importation de paquets superflue, 5-10 secondes (avec un bon IDE, ou une bonne connaissance de votre environnement de développement) pour le trouver et le réparer, et encore 8 secondes pour recompiler. Appelez-le 30 secondes au total - et maintenant toutes mes compilations futures restent dans les 10 secondes. Ou nous pouvons laisser notre module croître en incluant des dépendances inutiles, et regarder le temps de compilation grimper de 8 à 10, 12 ou 15 secondes. Cela ne semble pas énorme car nous sommes tous habitués à compiler des minutes de l'ordre de quelques minutes - mais quand vous commencez à vous rendre compte que la dégradation des performances est de 25%, vous vous arrêtez et réfléchissez pendant une minute.

Les temps de compilation sont déjà rapides. Considérons également que les vitesses des processeurs continuent d'augmenter (sinon autant qu'auparavant) et que le nombre de cœurs disponibles augmente également (et que la compilation de grandes quantités de code est bien adaptée au multithread). 200 000 lignes de code en 8 secondes aujourd'hui signifie qu'il n'est pas déraisonnable d'imaginer 200 000 lignes de code compilant essentiellement instantanément dans 10 ans. Je pense que l'équipe Go a délibérément pris la décision de faire du temps de compilation une chose du passé, et bien que le problème que vous soulevez ne soit qu'une petite partie de cela, il fait toujours partie de cela. Sur une autre note tout à fait, l'équipe Go semble également avoir développé une philosophie de conception de langage qui force certaines bonnes pratiques de programmation.À leur crédit, ils ont fait l'effort d'y parvenir sans pénalités de performance sérieuses, et ont largement réussi. [A part: Les deux seules choses que je peux penser de manière désinvolte qui impactent vraiment la performance sont la récupération de place et les variables initialisées de force - et cette dernière est assez triviale de nos jours.] Cela irrite royalement certains programmeurs, tout en rendant les autres heureux . C'est un vieux, vieux argument dans le monde de la programmation, et il est assez clair de quel côté Go est tombé, que ce soit ou non. Je pense que les deux forces ensemble ont influencé leur décision, et je pense qu'en fin de compte c'est un bon moyen d'y aller, bien que je soutienne d'autres commentateurs qui ont suggéré d'autoriser un drapeau "--strict" de rendre ce comportement particulier facultatif, en particulier pendant les premières étapes du cycle de vie d'un projet. Je pourrais facilement me voir définir des variables ou inclure des paquets quand je commence à écrire du code dont je sais que je vais avoir besoin plus tard, même si je n'ai pas encore écrit le code qui en a besoin.

+0

"Si le module A requiert le module B qui nécessite le module C, la plupart compilent C, compilent B et C (à nouveau), puis compilent A, B (à nouveau) et C (à nouveau), puis résolvent les problèmes de liaison. Non, ils ne le feraient pas. Ils compilent chaque fichier source une fois, puis les lient ensemble. –

+0

Nick, j'ai faussé légèrement, et mettra à jour ma réponse momentanément avec la correction. Cependant, si vous utilisez des fichiers d'en-tête en C/C++, vous vous retrouvez avec des portions ** ** de code qui sont compilées plusieurs fois. –

+0

Oui, les en-têtes sont inclus plusieurs fois, car ils sont gérés par le préprocesseur. Si vous avez des «gros» bits du code dans vos fichiers d'en-tête, UR DOIN IT WRONG. –

Questions connexes