Gibt es eine Möglichkeit, in Julia explizit zu verlangen (z. B. innerhalb eines Moduls oder Pakets), dass Typen deklariert werden müssen ? Hat zB oder Unterstützung für solche Überprüfungen? Bietet die Julia-Standarddistribution selbst einen statischen Code-Analysator oder ein gleichwertiges Gerät , mit dessen Hilfe diese Anforderung überprüft werden kann?PackageCompiler
Lint.jl
Nehmen wir als motivierendes Beispiel an, wir möchten sicherstellen, dass unsere wachsende Produktionscodebasis nur Code akzeptiert, der immer vom Typ deklariert ist , unter der Hypothese, dass große Codebasen mit Typdeklarationen tendenziell wartbarer sind.
Wenn wir diese Bedingung durchsetzen wollen, bietet Julia in ihrer Standardverteilung Mechanismen, um eine Typdeklaration zu erfordern, oder hilft sie, dieses Ziel zu erreichen? (zB irgendetwas, das über Linters, Commit-Hooks oder Ähnliches überprüft werden könnte?)
quelle
hasmethod(f, (Any,) )
zurückkehren,false
wenn kein Generikum definiert wurde. Sie müssten jedoch immer noch die Anzahl der Argumente anpassen (dhhasmethod(f, (Any,Any) )
für eine Funktion mit zwei Argumenten).Antworten:
Die kurze Antwort lautet: Nein, derzeit gibt es kein Tool zur Typprüfung Ihres Julia-Codes. Dies ist jedoch im Prinzip möglich, und in der Vergangenheit wurden einige Arbeiten in dieser Richtung durchgeführt, aber es gibt derzeit keinen guten Weg, dies zu tun.
Die längere Antwort lautet, dass "Typanmerkungen" hier ein roter Hering sind. Was Sie wirklich wollen, ist die Typprüfung, sodass der breitere Teil Ihrer Frage tatsächlich die richtige Frage ist. Ich kann ein wenig darüber sprechen, warum Typanmerkungen ein roter Hering sind, einige andere Dinge, die nicht die richtige Lösung sind, und wie die richtige Art von Lösung aussehen würde.
Das Erfordernis von Typanmerkungen erreicht wahrscheinlich nicht das, was Sie wollen: Man könnte einfach ein
::Any
beliebiges Feld, Argument oder einen beliebigen Ausdruck einfügen und es hätte eine Typanmerkung, aber keine, die Ihnen oder dem Compiler etwas Nützliches über den tatsächlichen Typ dieser Sache sagt. Es fügt viel visuelles Rauschen hinzu, ohne tatsächlich Informationen hinzuzufügen.Was ist mit konkreten Anmerkungen? Das
::Any
schließt aus, einfach alles anzuziehen (was Julia sowieso implizit tut). Es gibt jedoch viele vollkommen gültige Verwendungen von abstrakten Typen, die dies illegal machen würde. Zum Beispiel ist die Definition deridentity
FunktionWelche konkrete Typanmerkung würden Sie
x
unter dieser Anforderung anbringen? Die Definition gilt für jedenx
, unabhängig vom Typ - das ist der Punkt der Funktion. Die einzige korrekte Typanmerkung istx::Any
. Dies ist keine Anomalie: Es gibt viele Funktionsdefinitionen, die abstrakte Typen erfordern, um korrekt zu sein. Daher wäre es ziemlich einschränkend, diese zu zwingen, konkrete Typen zu verwenden, was für einen Julia-Code man schreiben kann.Es gibt einen Begriff von "Typstabilität", über den in Julia oft gesprochen wird. Der Begriff scheint aus der Julia-Community zu stammen, wurde aber von anderen dynamischen Sprachgemeinschaften wie R aufgegriffen. Die Definition ist etwas schwierig, bedeutet aber in etwa, dass Sie, wenn Sie die konkreten Arten der Argumente einer Methode kennen, Sie kennen auch die Art des Rückgabewerts. Selbst wenn eine Methode typstabil ist, reicht dies nicht aus, um eine Typprüfung zu gewährleisten, da die Typstabilität keine Regeln für die Entscheidung enthält, ob eine Typprüfung durchgeführt wird oder nicht. Dies geht jedoch in die richtige Richtung: Sie möchten überprüfen können, ob jede Methodendefinition typstabil ist.
Sie viele möchten keine Typstabilität benötigen, selbst wenn Sie könnten. Seit Julia 1.0 ist es üblich geworden, kleine Gewerkschaften einzusetzen. Dies begann mit der Neugestaltung des Iterationsprotokolls, das nun
nothing
anzeigt, dass die Iteration durchgeführt wird, anstatt ein(value, state)
Tupel zurückzugeben, wenn mehr Werte iteriert werden müssen. Diefind*
Funktionen in der Standardbibliothek verwenden auch einen Rückgabewert von,nothing
um anzuzeigen, dass kein Wert gefunden wurde. Dies sind technisch gesehen Instabilitäten, aber sie sind beabsichtigt und der Compiler kann recht gut darüber nachdenken, wie sie die Instabilität optimieren. Zumindest kleine Gewerkschaften müssen also wahrscheinlich im Code zugelassen sein. Außerdem gibt es keinen klaren Ort, um die Grenze zu ziehen. Obwohl man vielleicht sagen könnte, dass ein Rückgabetyp vonUnion{Nothing, T}
ist akzeptabel, aber nichts Unvorhersehbareres.Was Sie jedoch wahrscheinlich wirklich wollen, anstatt Typanmerkungen oder Typstabilität zu benötigen, ist ein Tool, das überprüft, ob Ihr Code keine Methodenfehler auslösen kann, oder allgemeiner gesagt, dass er keine unerwarteten Fehler auslöst. Der Compiler kann häufig genau bestimmen, welche Methode an jedem Aufrufstandort aufgerufen wird, oder sie zumindest auf einige Methoden eingrenzen. Auf diese Weise wird schneller Code generiert - der vollständige dynamische Versand ist sehr langsam (viel langsamer als beispielsweise vtables in C ++). Wenn Sie andererseits falschen Code geschrieben haben, gibt der Compiler möglicherweise einen bedingungslosen Fehler aus: Der Compiler weiß, dass Sie einen Fehler gemacht haben, teilt Ihnen dies jedoch erst zur Laufzeit mit, da dies die Sprachsemantik ist. Es könnte erforderlich sein, dass der Compiler bestimmen kann, welche Methoden an jedem Aufrufstandort aufgerufen werden können: Das würde garantieren, dass der Code schnell ist und keine Methodenfehler vorliegen. Das sollte ein gutes Tool zur Typprüfung für Julia tun. Es gibt eine gute Grundlage für diese Art von Dingen, da der Compiler bereits einen Großteil dieser Arbeit im Rahmen der Codegenerierung erledigt.
quelle
Dies ist eine interessante Frage. Die Schlüsselfrage ist, was wir als deklarierten Typ definieren . Wenn Sie meinen, dass
::SomeType
jede Methodendefinition eine Anweisung enthält, ist dies etwas schwierig, da Sie in Julia verschiedene Möglichkeiten zur dynamischen Codegenerierung haben. Vielleicht gibt es eine vollständige Lösung in diesem Sinne, aber ich weiß es nicht (ich würde es gerne lernen).Mir fällt jedoch ein, dass es relativ einfacher zu sein scheint, zu überprüfen, ob eine in einem Modul definierte Methode
Any
als Argument akzeptiert wird . Dies ist ähnlich, aber nicht äquivalent zu der früheren Aussage als:sehen für die
methods
Funktion gleich aus , da die Signatur beider Funktionenx
als akzeptiertAny
.Um nun zu überprüfen, ob eine Methode in einem Modul / Paket
Any
als Argument für eine der darin definierten Methoden akzeptiert wird, könnte etwas wie der folgende Code verwendet werden (ich habe es nicht ausführlich getestet, da ich es gerade aufgeschrieben habe, aber es scheint meistens mögliche Fälle abdecken):Wenn Sie es jetzt auf einem
Base.Iterators
Modul ausführen, erhalten Sie:und wenn Sie zB das Paket DataStructures.jl überprüfen, erhalten Sie:
Was ich vorschlage, ist keine vollständige Lösung für Ihre Frage, aber ich fand es nützlich für mich selbst und dachte darüber nach, es zu teilen.
BEARBEITEN
Der obige Code akzeptiert
f
wirdFunction
nur. Im Allgemeinen können Sie Typen haben, die aufgerufen werden können. Danncheck_declared(m::Module, f::Function)
könnte die Signatur in geändert werdencheck_declared(m::Module, f)
(tatsächlich würde dann die Funktion selbstAny
als zweites Argument zulassen :)) und alle ausgewerteten Namen an diese Funktion übergeben. Dann müssten Sie prüfen, ob die Funktionmethods(f)
positivlength
ist (wiemethods
bei nicht aufrufbaren Werten einen Wert mit Länge zurückgibt0
).quelle