Ich lese immer wieder über zerbrechliche Befehle, die man in beweglichen Argumenten mit \protect schützen muss. Was genau sind zerbrechliche Befehle und was sind bewegliche Argumente?

gefragt 14 Jun '13, 22:22

georg's gravatar image

georg
185447
Akzeptiert-Rate: 0%

bearbeitet 06 Aug '14, 17:21

gast3's gravatar image

gast3
(ausgesetzt)


Fangen wir mit den beweglichen Argumenten an. Beweglich bedeutet hier eigentlich etwas anderes: das entsprechende Argument wird vollständig expandiert. Dazu muss man grob verstehen, was es mit Expansion auf sich hat. Ein LaTeX-Makro wird im Laufe des Kompilations-Prozesses mit seinem Ersetzungstext ersetzt. Diesen Schritt nennt man Expansion.

\def\foo{foo} => `\foo' wird nach einer Expansion zu `foo'

Je nach Makro-Definition kann das ein oder mehrere Schritte beinhalten:

\def\a{a}
  => `a` wird nach einer Expansion zu `a'
\def\b{\a}
  => `\b' wird nach einer Expansion zu `\a' und nach zweien zu `a'
\def\c{\b}
  => `\c' wird nach einer Expansion zu `\b', nach zweien zu `\a' und nach dreien zu `a'

Kommt ein solches Makro nun in einer Definition vor, die mit \edef oder \xdef geschieht oder landet es im Argument des \write-Befehls, wird es vollständig expandiert:

 \edef\foo{\c} => `\foo' hat die Definition `a'

Da der \write-Befehl sein Argument expandiert und dieser nötig ist, um etwas in eine Hilfsdatei zu schreiben, sind die klassischen Stellen, an denen die Expansion problematisch ist, tatsächlich beweglich: Argumente von \section etwa, die im Kopf oder im Inhaltsverzeichnis landen (sich also an andere Stellen bewegen), oder die von \caption, die z.B. im Tabellenverzeichnis landen.

Warum kann die Expansion problematisch sein? Nun, nicht alle Befehle lassen sich expandieren. \def ist ein Standardbeispiel:

\edef\foo{\def\bla{blub}}
  => \edef wird versuchen, sein Argument zu expandieren;
     \def lässt sich nicht expandieren, also ist als nächstes \bla dran
     \bla ist nicht definiert, also wird eine Fehlermeldung ausgegeben

Zerbrechliche Befehle sind nun alle, die in einem \edef, \xdef oder \write zu einem Fehler führen, wo auch immer der Haken liegen mag. Eine Faustregel: Befehle mit einem optionalen Argument sind in der Regel zerbrechlich. Auch \textbf, \textit usw zerbrechen gerne mal, wenn man nicht damit rechnet. Ein klassisches Beispiel (ignorieren wir für den Moment, dass Fußnoten in Tabellenbeschriftungen sowieso fragwürdig sind):

\documentclass{article}
\begin{document}
\begin{table}
  Eine Tabelle
  \caption{Bla\footnote{blub}}
\end{table}
\end{document}

Dieser Code liefert den Fehler

! Argument of \@caption has an extra }.
<inserted text> 
                \par 
l.5   \caption{Bla\footnote{blub}}

Der Standardweg, den Fehler zu vermeiden, ist es, dem zerbrechlichen Befehl ein \protect voranzustellen. \protect ist ein cleveres Makro, das in verschiedenen Situationen eine eine jeweils andere Definition hat, um den entsprechenden Schutz liefern zu können.

\documentclass{article}
\begin{document}
\begin{table}
  Eine Tabelle
  \caption{Bla\protect\footnote{blub}}
\end{table}
\end{document}

Hat man e-TeX zur Verfügung, und das ist bei heutigen TeX-Installation eigentlich der Standardfall, dann kann man das betroffene Makro auch engine-protected machen. Das heißt, TeX bekommt mitgeteilt, dass dieses Makro (in \edef und Freunden) nicht expandierbar ist, ähnlich wie es bei \def von vornherein der Fall ist. Das etoolbox-Paket stellt dafür den bequemen Befehl \robustify zur Verfügung:

\documentclass{article}
\usepackage{etoolbox}
\robustify\footnote
\begin{document}
\begin{table}
  Eine Tabelle
  \caption{Bla\footnote{blub}}
\end{table}
\end{document}

Man sollte dazu sagen, dass es keine eindeutige Definition der Zerbrechlichkeit gibt, wie die Diskussion in den Kommentaren zeigt. Je nachdem, wie man sie definiert, kann Zerbrechlichkeit auch über die oben erwähnten Fälle hinaus gehen. Andere Definitionen wären etwa:

  • Ein Makro zerbricht, wenn das Ergebnis seines Einsatzes ein anderes ist, als man es von Einsätzen an anderen Stellen kennt. (Eine mir persönlich zu weit gehende Definition.)
  • Ein Makro ist zerbrechlich, wenn es durch den Einsatz von \protect vor dem Zerbrechen geschützt werden kann. (Eine Definition, die eher zu eng gefasst ist.)
Permanenter link

beantwortet 15 Jun '13, 18:17

cgnieder's gravatar image

cgnieder
22.1k253463
Akzeptiert-Rate: 60%

bearbeitet 17 Aug '13, 12:13

Ein bewegliches Argument muss AFAIK nicht unbedingt vollständig expandiert werden. Auch eine Teilexpansion (beispielsweise mit expandafter) kann bereits ein Problem darstellen. Ein bewegliches Argument ist daher ein Argument, das von dem verarbeitenden Makro (ganz oder teilweise) expandiert wird. Übrigens sind auch Befehle mit einer Sternform wie \vspace in der Regel zerbrechlich.

(21 Jun '13, 11:10) saputello

@saputello Stimmt, Befehle mit Sternvarianten sind auch Kandidaten fürs Zerbrechen. Für ein Zerbrechen durch \expandafter würde ich aber gerne ein Beispiel sehen. Mein Verständnis des Zerbrechens in einem beweglichen Argument ist, dass die Expansion des fragilen Makros nicht in der vom Erfinder dafür vorgesehenen Reihenfolge geschieht (eben wegen nicht expandierbarer Bestandteile). Das scheint mir mit \expandafters deutlich schwieriger zu sein...

(21 Jun '13, 11:23) cgnieder

Alles, was nicht als robust, beziehungsweise nicht expandierbar, definiert ist oder kein TeX-Primitiv ist, macht Probleme. Also fast alles unter LaTeX.

(21 Jun '13, 12:28) Herbert

@Clemens Als Kommentar ist das schwer darstellbar, aber trotzdem: \def\ifequal#1#2{\expandafter\ifx #1#2 true\else false\fi} \def\a{a} \def\ab{\a b} \def\AB{\a b} \ifequal{\ab}{\AB} \bye Hier wird das erste Argument zunächst nicht voll, sondern nur eine Stufe weit expandiert, aber trotzdem zerbricht es. Natürlich würde das kein (vernünftiger) Mensch so schreiben, aber Beispiele sind nun einmal desöfteren an den Haaren herbeigezogen. Dass es mit \expandafter nicht so einfach ist, ein Beispiel zu finden, ist natürlich richtig.

(21 Jun '13, 12:35) saputello

@saputello ich weiß nicht, ob ich das „Zerbrechen” nennen würde, es gibt ja keine Fehlermeldung oder etwas dergleichen. Die TeX FAQ beschreibt einen zerbrechlichen Befehl als „it’s a command that expands into illegal TeX code during the save process.“ und das passiert her ja nicht

(21 Jun '13, 12:46) cgnieder

@Clemens: Wenn Du als erstes Argument an \ifequal statt \ab beispielsweise \BA übergibst, dann zerbricht es auch zu einer Fehlermeldung, statt nur zu einem für den Anwender unerwarteten Ergebnis. Ich halte die englische TeX-FAQ an der Stelle im übrigen für zu eng gefasst. Nicht nur Code, der eine Fehlermeldung liefert ist fehlerhaft. Das gilt ebenso für Code, der falsche Ergebnisse liefert.

(21 Jun '13, 12:59) saputello

@saputello sicher, \BA ist ja nicht definiert. Meiner Meinung nach ist zerbrechlich aber nicht das gleiche wie gibt eine Fehlermeldung oder ein unerwartetes Ergebnis. Damit bin ich auch nicht alleine: http://tex.stackexchange.com/questions/4736/what-is-the-difference-between-fragile-and-robust-commands

(21 Jun '13, 13:04) cgnieder

@Clemens: Es muss beim Zerbrechen nicht notwendigerweise einen Fehler geben; entscheidend ist eher, dass der ursprüngliche Effekt des zerbrochenen Makros nicht mehr gegeben ist.

(21 Jun '13, 13:24) Herbert

@Herbert ok stimmt. Dennoch will ich Zerbrechen nicht gleichsetzen mit „gibt was anderes als erwartet, möglicherweise einen Fehler“ sondern mit „gibt in einem Exansionskontext etwas anderes als erwartet, möglicherweise einen Fehler“ (wobei Expansionskontext x- und vermutlich auch f-Expansion in der LaTeX3-Sprache ist), da das in allen Quellen, die mir geläufig sind, die gängige Interpretation von zerbrechlich ist. Das \ifequal-Beispiel fällt IMHO nicht darunter. (Ein robustes \ab würde trotzdem zu false führen.)

(21 Jun '13, 13:35) cgnieder

@saputello Sehe ich auch so wie Clemens: Das Beispiel zeigt kein Problem. Eine Folge von Tokens ist nur dann zerbrechlich, wenn die Tokens auch Zuweisungen enthalten und die korrekte Expansion dieser Tokenfolge von der Ausführung dieser Zuweisungen abhängig ist. Gibt es keine Zuweisungen/Seiteneffekte, gibt es erst einmal keine Probleme. Und sowohl expandafter, ifx, else und fi sind rein expandierbar.

Genau die Zuweisungen sind ja das Problem von "fragilen" Dingen in "moving arguments": Hier (also in einem write oder einem mark) wird nur expandiert, ohne Zuweisungen.

(28 Jun '13, 21:26) bernd

Mmmh, auch vollständig expandierbare Dinge können zerbrechen: Wenn man \ifvmode, \ifmmode verwendet, gibt es evtl. Probleme, wenn die Expansion zum falschen Zweig führt, weil vor dem if in den anderen Mode gewechselt würde, wenn man das Makro "normal" ausführt.

(28 Jun '13, 21:29) bernd

@bernd Letztlich stimmt ich Clemens in soweit zu, dass es am Ende eine Frage davon ist, was man nun als zerbrechen definiert und was nicht. Persönlich wäre ich mit der Behauptung dass nur vollständige Expansion ein Problem darstellt, einfach etwas vorsichtig. Denn am Ende kommt es dann eben doch weniger auf die Definition als vielmehr darauf an, ob es so funktioniert, wie der Anwender erwartet. ;)

(04 Jul '13, 15:41) saputello
Ergebnis 5 von 12 show 7 more comments
Deine Antwort
Vorschau umschalten

Folgen dieser Frage

Per E-Mail:

Wenn sie sich anmelden, kommen Sie für alle Updates hier in Frage

Per RSS:

Antworten

Antworten und Kommentare

Markdown-Grundlagen

  • *kursiv* oder _kursiv_
  • **Fett** oder __Fett__
  • Link:[Text](http://url.com/ "Titel")
  • Bild?![alt Text](/path/img.jpg "Titel")
  • nummerierte Liste: 1. Foo 2. Bar
  • zum Hinzufügen ein Zeilenumbruchs fügen Sie einfach zwei Leerzeichen an die Stelle an der die neue Linie sein soll.
  • grundlegende HTML-Tags werden ebenfalls unterstützt

Frage-Themen:

×52
×7

gestellte Frage: 14 Jun '13, 22:22

Frage wurde gesehen: 14,058 Mal

zuletzt geändert: 06 Aug '14, 17:21