Existe-t-il un moyen d'exiger explicitement dans Julia (par exemple dans un module ou un package) que les types doivent être déclarés ? Existe-t-il, par exemple, PackageCompiler
ou Lint.jl
a-t-il un support pour de tels contrôles? Plus largement, la distribution standard Julia fournit-elle elle-même un analyseur de code statique ou équivalent qui pourrait aider à vérifier cette exigence?
Par exemple, disons que nous voulons nous assurer que notre base de code de production croissante n'accepte que du code qui est toujours de type déclaré , sous l'hypothèse que les grandes bases de code avec des déclarations de type ont tendance à être plus maintenables.
Si nous voulons appliquer cette condition, Julia dans sa distribution standard fournit-elle des mécanismes pour exiger la déclaration de type ou aider à faire avancer cet objectif? (par exemple, tout ce qui pourrait être vérifié via des linters, des hooks de validation ou l'équivalent?)
la source
hasmethod(f, (Any,) )
il reviendrafalse
si aucun générique n'a été défini. Vous devez cependant toujours faire correspondre le nombre d'arguments (c'est-hasmethod(f, (Any,Any) )
à- dire pour une fonction à deux arguments).Réponses:
La réponse courte est: non, il n'y a actuellement aucun outil pour vérifier le type de votre code Julia. C'est possible en principe, cependant, et un certain travail a été fait dans ce sens dans le passé, mais il n'y a pas de bonne façon de le faire pour le moment.
La réponse la plus longue est que les "annotations de type" sont un hareng rouge ici, ce que vous voulez vraiment, c'est la vérification de type, donc la partie la plus large de votre question est en fait la bonne question. Je peux parler un peu de la raison pour laquelle les annotations de type sont un hareng rouge, d'autres choses qui ne sont pas la bonne solution et à quoi ressemblerait le bon type de solution.
Exiger des annotations de type n'atteint probablement pas ce que vous voulez: on pourrait simplement mettre
::Any
n'importe quel champ, argument ou expression et il aurait une annotation de type, mais pas une qui vous dit ou qui compile quoi que ce soit d'utile sur le type réel de cette chose. Il ajoute beaucoup de bruit visuel sans ajouter réellement d'informations.Pourquoi ne pas exiger des annotations de type concret? Cela exclut de tout mettre
::Any
(ce que Julia fait implicitement de toute façon). Cependant, il existe de nombreuses utilisations parfaitement valides des types abstraits que cela rendrait illégaux. Par exemple, la définition de laidentity
fonction estQuelle annotation de type concret mettriez-vous
x
sous cette exigence? La définition s'applique à toutx
, quel que soit le type — c'est en quelque sorte le but de la fonction. La seule annotation de type correcte estx::Any
. Ce n'est pas une anomalie: il existe de nombreuses définitions de fonctions qui nécessitent des types abstraits pour être correctes, donc les forcer à utiliser des types concrets serait assez limitant en termes de type de code Julia que l'on peut écrire.Il y a une notion de «stabilité de type» dont on parle souvent dans Julia. Le terme semble provenir de la communauté Julia, mais a été repris par d'autres communautés linguistiques dynamiques, comme R. C'est un peu délicat à définir, mais cela signifie en gros que si vous connaissez les types concrets des arguments d'une méthode, vous connaissez également le type de sa valeur de retour. Même si une méthode est de type stable, ce n'est pas tout à fait suffisant pour garantir qu'elle vérifierait le type car la stabilité de type ne parle pas de règles pour décider si quelque chose vérifie ou non. Mais cela va dans la bonne direction: vous voudriez pouvoir vérifier que chaque définition de méthode est de type stable.
Beaucoup ne veulent pas exiger la stabilité du type, même si cela est possible. Depuis Julia 1.0, il est devenu courant d'utiliser de petits syndicats. Cela a commencé avec la refonte du protocole d'itération, qui utilise désormais
nothing
pour indiquer que l'itération est effectuée par rapport au retour d'un(value, state)
tuple lorsqu'il y a plus de valeurs à itérer. Lesfind*
fonctions de la bibliothèque standard utilisent également une valeur de retour denothing
pour indiquer qu'aucune valeur n'a été trouvée. Ce sont des instabilités de type technique, mais elles sont intentionnelles et le compilateur est assez bon pour les raisonner en optimisant autour de l'instabilité. Donc, au moins les petits syndicats doivent probablement être autorisés dans le code. De plus, il n'y a pas de place claire pour tracer la ligne. Bien que l'on puisse peut-être dire qu'un type de retour deUnion{Nothing, T}
est acceptable, mais rien de plus imprévisible que cela.Ce que vous voulez probablement vraiment, cependant, plutôt que d'exiger des annotations de type ou la stabilité de type, c'est d'avoir un outil qui vérifiera que votre code ne peut pas générer d'erreurs de méthode, ou peut-être plus largement qu'il ne générera aucune sorte d'erreur inattendue. Le compilateur peut souvent déterminer avec précision quelle méthode sera appelée sur chaque site d'appel, ou au moins la restreindre à quelques méthodes. C'est ainsi qu'il génère du code rapide - la répartition dynamique complète est très lente (beaucoup plus lente que vtables en C ++, par exemple). Si vous avez écrit un code incorrect, en revanche, le compilateur peut émettre une erreur inconditionnelle: le compilateur sait que vous avez fait une erreur mais ne vous le dit qu'au moment de l'exécution car ce sont les sémantiques du langage. On pourrait exiger que le compilateur puisse déterminer quelles méthodes peuvent être appelées sur chaque site d'appel: cela garantirait que le code sera rapide et qu'il n'y a aucune erreur de méthode. C'est ce qu'un bon outil de vérification de type pour Julia devrait faire. Il y a une bonne base pour ce genre de chose puisque le compilateur fait déjà une grande partie de ce travail dans le cadre du processus de génération de code.
la source
C'est une question intéressante. La question clé est ce que nous définissons comme type déclaré . Si vous voulez dire qu'il y a une
::SomeType
déclaration dans chaque définition de méthode, il est quelque peu difficile à faire car vous avez différentes possibilités de génération de code dynamique dans Julia. Il y a peut-être une solution complète dans ce sens mais je ne la connais pas (j'adorerais l'apprendre).La chose qui me vient à l'esprit cependant, qui semble relativement plus simple à faire, est de vérifier si une méthode définie dans un module accepte
Any
comme argument. Ceci est similaire mais pas équivalent à la déclaration précédente:la même
methods
fonction pour la fonction que la signature des deux fonctions acceptex
commeAny
.Maintenant, pour vérifier si une méthode dans un module / package accepte
Any
comme argument pour l'une des méthodes définies dans celui-ci, quelque chose comme le code suivant pourrait être utilisé (je ne l'ai pas testé de manière approfondie car je viens de l'écrire, mais il semble couvrir les cas possibles):Maintenant, lorsque vous l'exécutez sur le
Base.Iterators
module, vous obtenez:et lorsque vous vérifiez par exemple le package DataStructures.jl, vous obtenez:
Ce que je propose n'est pas une solution complète à votre question mais je l'ai trouvée utile pour moi donc j'ai pensé à la partager.
ÉDITER
Le code ci-dessus accepte
f
d'êtreFunction
uniquement. En général, vous pouvez avoir des types pouvant être appelés. Ensuite, lacheck_declared(m::Module, f::Function)
signature pourrait être modifiée encheck_declared(m::Module, f)
(en fait, la fonction elle-même le permettraitAny
comme deuxième argument :)) et passer tous les noms évalués à cette fonction. Ensuite, vous devrez vérifier simethods(f)
a positiflength
dans la fonction (commemethods
pour les non-callables renvoie une valeur qui a une longueur0
).la source