Ich schreibe eine Funktion, die im Prinzip eine beliebige Anzahl von Argumenten akzeptiert. In der Praxis sollte jedoch immer nur eine gerade Anzahl von Argumenten übergeben werden, und ansonsten werden unerwünschte Ergebnisse erzielt.
Hier ist ein Dummy-Beispiel für den Kontext:
(defun my-caller (&rest args)
(while args
(call-other-function (pop args) (pop args))))
Wenn eine Elisp-Datei bytemäßig kompiliert wird, gibt der Byte-Compiler eine Warnung aus, wenn eine Funktion mit der falschen Anzahl von Argumenten aufgerufen wird. Offensichtlich wird das nie passieren my-caller
, da es so definiert ist, dass es eine beliebige Anzahl annehmen kann.
Vielleicht gibt es noch eine Symboleigenschaft, die ich festlegen kann, oder ein (declare)
Formular, das ich zu seiner Definition hinzufügen kann. Etwas, das den Benutzer darauf hinweist, dass diese Funktion nur mit einer geraden Anzahl von Argumenten versehen werden sollte.
- Gibt es eine Möglichkeit, den Byte-Compiler über diese Einschränkung zu informieren?
- Wenn nicht, ist es mit einem Makro anstelle einer Funktion möglich?
quelle
Antworten:
BEARBEITEN : Eine bessere Möglichkeit, dies in neueren Emacs zu tun, besteht darin, ein Compiler-Makro zu definieren , um die Anzahl der Argumente zu überprüfen. Meine ursprüngliche Antwort unter Verwendung eines normalen Makros wird im Folgenden beibehalten, aber ein Compiler-Makro ist überlegen, da es die Übergabe der Funktion an
funcall
oderapply
zur Laufzeit nicht verhindert .In neueren Versionen von Emacs können Sie dazu ein Compiler-Makro für Ihre Funktion definieren, das die Anzahl der Argumente überprüft und eine Warnung (oder sogar einen Fehler) ausgibt, wenn diese nicht übereinstimmt. Die einzige feine Sache ist, dass das Compiler-Makro das ursprüngliche Funktionsaufrufformular zur Auswertung oder Kompilierung unverändert zurückgeben soll. Dazu wird ein
&whole
Argument verwendet und dessen Wert zurückgegeben. Dies könnte folgendermaßen geschehen:Beachten Sie, dass
funcall
undapply
jetzt verwendet werden können, sie jedoch die Argumentprüfung durch das Compiler-Makro umgehen. Trotz ihres Namens scheinen Compiler-Makros auch im Zuge der 'interpretierten' Auswertung über erweitert zu C-xC-ewerden M-xeval-buffer, so dass Sie Fehler beim Auswerten sowie beim Kompilieren dieses Beispiels bekommen.Die ursprüngliche Antwort lautet:
Hier sehen Sie, wie Sie Jordons Vorschlag umsetzen können, "ein Makro zu verwenden, das beim Erweitern Warnungen ausgibt". Es stellt sich als sehr einfach heraus:
Der Versuch, die obigen Informationen in einer Datei zu kompilieren, schlägt fehl (es wird keine
.elc
Datei erstellt). Im Kompilierungsprotokoll wird eine anklickbare Fehlermeldung angezeigt, die Folgendes angibt:Sie könnten auch ersetzen
(error …)
mit(byte-compile-warn …)
einer Warnung statt einem Fehler zu erzeugen, so dass Kompilation fortzusetzen. (Danke an Jordon für den Hinweis in den Kommentaren).Da Makros zur Kompilierungszeit erweitert werden, ist mit dieser Prüfung keine Laufzeitstrafe verbunden. Natürlich können Sie andere Personen nicht davon abhalten,
my-caller--function
direkt anzurufen , aber Sie können es zumindest als "private" Funktion unter Verwendung der Konvention mit zwei Bindestrichen bewerben.Ein bemerkenswerter Nachteil der Verwendung eines Makros für diesen Zweck ist, dass
my-caller
es keine erstklassige Funktion mehr ist: Sie können es nicht anfuncall
oderapply
zur Laufzeit übergeben (oder es wird zumindest nicht das tun, was Sie erwarten). Insofern ist diese Lösung nicht ganz so gut, als eine Compiler-Warnung für eine echte Funktion deklarieren zu können. Die Verwendung vonapply
würde es natürlich unmöglich machen, die Anzahl der Argumente zu überprüfen, die zur Kompilierungszeit an die Funktion übergeben werden. Vielleicht ist dies also ein akzeptabler Kompromiss.quelle
byte-compile-warn
apply
oderfuncall
den Makro - Wrapper. Ich werde es ausprobieren und meine Antwort bearbeiten, wenn es funktioniert.Ja, das kannst du benutzen
byte-defop-compiler
von eine Funktion angeben, die Ihre Funktion kompiliert. Esbyte-defop-compiler
sind einige nützliche Funktionen integriert, mit denen Sie festlegen können, dass Ihre Funktionen basierend auf einer Reihe von Argumenten Warnungen ausgeben sollen.Dokumentation
Fügen Sie eine Compiler-Form für FUNCTION hinzu. Wenn function ein Symbol ist, muss die Variable "byte-SYMBOL" den zu verwendenden Opcode benennen. Wenn function eine Liste ist, ist das erste Element die Funktion und das zweite Element das Bytecode-Symbol. Das zweite Element kann null sein, was bedeutet, dass es keinen Opcode gibt. COMPILE-HANDLER ist die Funktion, die zum Kompilieren dieses Byte-Ops verwendet wird, oder kann die Abkürzungen 0, 1, 2, 3, 0-1 oder 1-2 haben. Wenn es Null ist, dann ist der Handler "Byte-Compile-SYMBOL".
Verwendung
In Ihrem speziellen Fall können Sie eine der Abkürzungen verwenden, um zu definieren, dass Ihre Funktion zwei Argumente erhalten soll.
Jetzt gibt Ihre Funktion Warnungen aus, wenn sie mit etwas anderem als 2 Argumenten kompiliert wird.
Wenn Sie spezifischere Warnungen geben und Ihre eigenen Compilerfunktionen schreiben möchten. Schauen Sie sich
byte-compile-one-arg
und andere ähnliche Funktionen in bytecomp.el als Referenz an.Beachten Sie, dass Sie nicht nur eine Funktion für die Validierung angeben, sondern auch das Kompilieren. Wieder Kompilierungsfunktionen in bytecomp.el bieten Ihnen eine gute Referenz.
Sicherere Routen
Dies ist nicht etwas, was ich online dokumentiert oder diskutiert habe, aber insgesamt würde ich sagen, dass dies ein schlechter Weg ist. Der richtige Weg (IMO) wäre, Ihre Defuns mit beschreibenden Signaturen zu schreiben oder ein Makro zu verwenden, das zur Expansionszeit Warnungen ausgibt, die Länge Ihrer Argumente überprüft und mit
byte-compile-warn
odererror
Fehler anzeigt . Es kann auch von Vorteil sein, wenn Sie davon Gebrauch macheneval-when-compile
, Fehlerprüfungen durchzuführen.Sie müssen auch Ihre Funktion definieren, bevor sie jemals verwendet wird, und den Aufruf an
byte-defop-compiler
muss erfolgen, bevor der Compiler zu den tatsächlichen Aufrufen Ihrer Funktion gelangt.Auch hier scheint es nicht wirklich dokumentiert oder empfohlen zu sein, was ich gesehen habe (könnte falsch sein), aber ich stelle mir vor, dass das hier zu befolgende Muster darin besteht, eine Art Header-Datei für Ihr Paket anzugeben, die voll von leeren Defuns ist und ruft an
byte-defop-compiler
. Dies wäre im Grunde ein Paket, das benötigt wird, bevor Ihr echtes Paket kompiliert werden kann.Meinung: Aufgrund meines Wissens, das nicht viel ist, weil ich gerade von all dem erfahren habe, würde ich Ihnen raten, nichts davon zu tun. je
quelle