edef geht nich (falsch verstanden?) / Fußn. ähnlicher Befehl

Redefinition von Makros, Definition eigener Befehle sowie neuer Umgebungen


Benutzeravatar
iTob
Forum-Meister
Forum-Meister
Beiträge: 1221
Registriert: Mo 19. Apr 2010, 22:19
Kontaktdaten:

edef geht nich (falsch verstanden?) / Fußn. ähnlicher Befehl

Beitrag von iTob »

Hallo Forum!

Ich würde gerne eine Umgebung definieren, innerhalb derer, mittels einem eigenen Befehl \note erstellte, Anmerkungen gesammelt und anschließend als eine Art Fußnote ausgegeben werden.
Im Minimalbeispiel funktioniert es auch schon wie gewünscht, nur dass in der Liste nicht der jeweils aktuelle Zähle gespeichert wir, sondern der unexpandierte Befehl, was dazu fürht, dass bei der Ausgabe alle Anmerkungen mit der gleichen (letzten Zahl) versehen werden.

Hier das Beispiel:
\documentclass[11pt,a4paper]{scrartcl}
\usepackage[latin1]{inputenc}
\usepackage{ifthen}


\makeatletter

\newcommand{\@srcnumnotes}{}
\newcommand{\note}[1]{}
\newcounter{notecnt}
\setcounter{notecnt}{0}
\newcommand{\notecntfmt}[1]{\roman{#1}}


\newenvironment{btmnotesrc}{%
	\par\addvspace{\baselineskip}%
	\renewcommand{\@srcnumnotes}{}%
	\renewcommand{\note}[1]{%
		\refstepcounter{notecnt}%	
		\rule{0.075em}{0pt}\textsuperscript{\notecntfmt{notecnt}}%
		\edef\@tmpnote{\notecntfmt{notecnt}}%
		\g@addto@macro\@srcnumnotes{ \qquad \textsuperscript{\@tmpnote}\,##1}%
	}%
}{%	
		\ifthenelse{\equal{\@srcnumnotes}{}}{%
			% wenn leer, nix machen
		}{%
			% wenn etwas drin, ausgeben
			\par\footnotesize\@srcnumnotes%
		}%
	\par\addvspace{\baselineskip}% add vertical space
	\noindent\ignorespaces%
}
\makeatother

\begin{document}
\section*{\texttt{edef}-Probleme}
Text vorher.
\begin{btmnotesrc}
Ein\note{Anmerkung1} Holzschuhmacher\note{Anmerkung2} und\note{Anmerkung3} ein\note{Anmerkung4}
Bogenschutze mit Brot- beziehungsweise Wassersack durchschritten
eine Saccharose-Pfutze. Zwar\note{Anm1} war\note{Anm2} sie\note{Anm3} gottlos, aber zah
wie Lack.
\end{btmnotesrc}
Text hinterher.
\end{document}
Ich dachte eigentlich, dass \edef den expandierten Inhalt im Makro (hier: \@tmpnote) speichert. Hab ich das falsch verstanden oder falsch eingesetzt?

Die Definition des \note-Makros innerhalb der Umgebung mache ich, weil es nur in der Umgebung so funktionieren darf und außerhalb und in einer anderen Umgebung eine andere Wirkung haben soll.


Vielen Dank und Grüße!
Tobi

PS: Was ist der unterschied zwischen \addto und \g@addto@macro

Benutzeravatar
KOMA
TeX-Entwickler
TeX-Entwickler
Beiträge: 2958
Registriert: Fr 4. Jul 2008, 17:28
Kontaktdaten:

Beitrag von KOMA »

Der Unterschied zwischen \addto und \g@addto@macro ist, dass \addto eine babel-Anweisung ist, die nur vorhanden ist, wenn babel geladen ist, und im Falle, dass die zu erweiternde Anweisung noch nicht definiert ist, diese neu definiert wird, während \g@addto@macro im LaTeX-Kern definiert ist und im Falle, dass eine nicht definierte Anweisung erweitert werden soll, ein Fehler ausgegeben wird.

\edef dürfte in Deinem Beispiel übrigens nicht das Problem sein, auch wenn man unter LaTeX in der Regel eher \protected@edef verwenden sollte. Das Problem ist, dass Du \g@addto@macro verwendest. Dadurch wird dann \@srcnumnotes u. a. um das nicht expandierte \@tmpnote erweitert. Es wird also jedes Mal das \@tmpnote expandiert, das dann definiert ist, wenn \@scrnumnotes später expandiert wird. Du siehst das leicht, wenn Du zu Debuggingzwecken einige \show einfügst:
\newenvironment{btmnotesrc}{%
   \par\addvspace{\baselineskip}%
   \renewcommand{\@srcnumnotes}{}%
   \renewcommand{\note}[1]{%
      \refstepcounter{notecnt}%  
      \rule{0.075em}{0pt}\textsuperscript{\notecntfmt{notecnt}}%
      \edef\@tmpnote{\notecntfmt{notecnt}}%
      \show\@tmpnote
      \g@addto@macro\@srcnumnotes{ \qquad \textsuperscript{\@tmpnote}\,##1}%
      \show\@scrnumnotes
   }%
}{%  
      \ifthenelse{\equal{\@srcnumnotes}{}}{%
         % wenn leer, nix machen
      }{%
         % wenn etwas drin, ausgeben
         \show\@scrnumnotes
         \par\footnotesize\@srcnumnotes%
      }%
   \par\addvspace{\baselineskip}% add vertical space
   \noindent\ignorespaces%
}
Probier zur Lösung mal \protected@edef, beispielsweise (ungetestet):
\protected@edef\@scrnumnotes{\@scrnumnotes\protect\qquad\protect\textsuperscript{\@tmpnote}\,##1}
Disclaimer: Ich habe mir nicht näher angesehen, was Du da eigentlich machst, sondern mich nur allein an der Theorie von Definition und Verwendung orientiert. Ich vermute aus dem Augenwinkel fast, dass stattdessen eine Verwendung einer minipage mit \footnote innerhalb der minipage eine hinreichende Lösung wäre.

Benutzeravatar
iTob
Forum-Meister
Forum-Meister
Beiträge: 1221
Registriert: Mo 19. Apr 2010, 22:19
Kontaktdaten:

Beitrag von iTob »

KOMA hat geschrieben:Disclaimer: Ich habe mir nicht näher angesehen, was Du da eigentlich machst, sondern mich nur allein an der Theorie von Definition und Verwendung orientiert. Ich vermute aus dem Augenwinkel fast, dass stattdessen eine Verwendung einer minipage mit \footnote innerhalb der minipage eine hinreichende Lösung wäre.
Nabend KOMA und vielen Dank,

diese Idee hatte ich auch schon, hab sie aber noch nicht getestet. Außerdem würde ich es eigentlich gerne selbst implementieren.
Werde mir morgen mal deinen Vorschlag anschauen...

Gute Nacht!
Tobi

Benutzeravatar
iTob
Forum-Meister
Forum-Meister
Beiträge: 1221
Registriert: Mo 19. Apr 2010, 22:19
Kontaktdaten:

Beitrag von iTob »

Hallo,

ich bin jetzt endlich dazu gekommen, deinen Vorschlag zu testen und es klappt :D
Aber: Es geht nur solange ich die Zeilen nicht nummerieren lasse. Wenn ich das Beispiel um eine linenumbers-Umgebung ergänze, klappt es nicht mehr. Ich nehme mal an, weil \@srcnumnotes dann nur innerhalb der Umgebung definiert wird. Wie bekomme ich es denn global hin?
Wenn ich einfach \global davor schreibe, scheint es keinen unterschied zu machen.

Hier das neue Beispiel:
\documentclass[11pt,a4paper]{scrartcl}
\usepackage[latin1]{inputenc}
\usepackage{ifthen}
\usepackage{lineno}


\makeatletter

\newcommand{\@srcnumnotes}{}
\newcommand{\@tmpnote}{}
\newcommand{\note}[1]{}
\newcounter{notecnt}
\setcounter{notecnt}{0}
\newcommand{\notecntfmt}[1]{\roman{#1}}

\newenvironment{btmnotesrc}{%
	\par\addvspace{\baselineskip}%
	\renewcommand{\@srcnumnotes}{}%
	\renewcommand{\note}[1]{%
		\refstepcounter{notecnt}%	
		\rule{0.075em}{0pt}\textsuperscript{\notecntfmt{notecnt}}%
		\global\protected@edef\@tmpnote{\notecntfmt{notecnt}}%
%		\show\@tmpnote
		\global\protected@edef\@srcnumnotes{\@srcnumnotes\protect\qquad\protect\textsuperscript{\@tmpnote}\,##1}%
	}%
%%% ergaenzte Umgebung, wenn man die auskommentiert, geht es wie es soll...
	\begin{linenumbers}
}{%	
	\end{linenumbers}
		\ifthenelse{\equal{\@srcnumnotes}{}}{%
			% wenn leer, nix machen
		}{%
			% wenn etwas drin, ausgeben
			\par\footnotesize\@srcnumnotes%
		}%
	\par\addvspace{\baselineskip}% add vertical space
	\noindent\ignorespaces%
}
\makeatother

\begin{document}
\section*{\texttt{edef}-Probleme}
Text vorher.
\begin{btmnotesrc}
Ein\note{Anmerkung1} Holzschuhmacher\note{Anmerkung2} und\note{Anmerkung3} ein\note{Anmerkung4}
Bogenschutze mit Brot- beziehungsweise Wassersack durchschritten
eine Saccharose-Pfutze. Zwar\note{Anm1} war\note{Anm2} sie\note{Anm3} gottlos, aber zah
wie Lack.
\end{btmnotesrc}
Text hinterher.
\end{document}
Und noch zwei Fragen:
1. Warum sollte man den \protected@edef verwenden statt \edef?
2. Wann genau benötige ich denn ein \protect, kann man das überhaupt so allgemein sagen?

Nachmal danke!
Tobi

PS: Gibt es eine Quelle, in der solche Dinge (z.B. Komandos wie \protected@edef) nachzulesen / zu lernen sind. Das texboook habe ich mir schon runtergeladen, aber bisher nur als Nachschlagewerk benutzt.

Benutzeravatar
iTob
Forum-Meister
Forum-Meister
Beiträge: 1221
Registriert: Mo 19. Apr 2010, 22:19
Kontaktdaten:

Beitrag von iTob »

Guten Morgen :)

Ich hab jetzt selbst di lösung gefunden und statt
\protected@xdef
% -->
\global\protected@edef
verwendet. Es belibt nur die Frage, warum das anders nicht geht. Ich dachte \global würde eine Definition Global wirksam werden lassen...??

Hier also das lauffähige Beispiel:
\documentclass[11pt,a4paper]{scrartcl}
\usepackage[latin1]{inputenc}
\usepackage{ifthen}
\usepackage{lineno}

\makeatletter

\newcommand{\@srcnumnotes}{}
\newcommand{\@tmpnote}{}
\newcommand{\note}[1]{}
\newcounter{notecnt}
\setcounter{notecnt}{0}
\newcommand{\notecntfmt}[1]{\roman{#1}}

\newenvironment{btmnotesrc}{%
	\par\addvspace{\baselineskip}%
	\renewcommand{\@srcnumnotes}{}%
	\renewcommand{\note}[1]{%
		\refstepcounter{notecnt}%	
		\rule{0.075em}{0pt}\textsuperscript{\notecntfmt{notecnt}}%
		\protected@xdef\@tmpnote{\notecntfmt{notecnt}}%
%		\show\@tmpnote
		\protected@xdef\@srcnumnotes{\@srcnumnotes\protect\qquad\protect\textsuperscript{\@tmpnote}\,##1}%
	}%
	\begin{linenumbers}
}{%	
	\end{linenumbers}
		\ifthenelse{\equal{\@srcnumnotes}{}}{%
			% wenn leer, nix machen
		}{%
			% wenn etwas drin, ausgeben
			\par\footnotesize\@srcnumnotes%
		}%
	\par\addvspace{\baselineskip}% add vertical space
	\noindent\ignorespaces%
}
\makeatother

\begin{document}
\section*{\texttt{edef}-Probleme}
Text vorher.
\begin{btmnotesrc}
Ein\note{Anmerkung1} Holzschuhmacher\note{Anmerkung2} und\note{Anmerkung3} ein\note{Anmerkung4}
Bogenschutze mit Brot- beziehungsweise Wassersack durchschritten
eine Saccharose-Pfutze. Zwar\note{Anm1} war\note{Anm2} sie\note{Anm3} gottlos, aber zah
wie Lack.
\end{btmnotesrc}
Text hinterher.


\end{document}
Und aus dem letzten Post noch unbeantwortet geblieben:
iTob hat geschrieben: Und noch zwei Fragen:
1. Warum sollte man den \protected@edef verwenden statt \edef?
2. Wann genau benötige ich denn ein \protect, kann man das überhaupt so allgemein sagen?
PS: Gibt es eine Quelle, in der solche Dinge (z.B. Komandos wie \protected@edef) nachzulesen / zu lernen sind. Das texboook habe ich mir schon runtergeladen, aber bisher nur als Nachschlagewerk benutzt.
(Wegen dieser offenen Fragen hab ich auch den Status noch nicht auf beantwortet gestellt...)

Viele Grüße!
Tobi

Benutzeravatar
KOMA
TeX-Entwickler
TeX-Entwickler
Beiträge: 2958
Registriert: Fr 4. Jul 2008, 17:28
Kontaktdaten:

Beitrag von KOMA »

\global wirkt nur auf bestimmte Primitive, beispielsweise \let, \def, \edef. Wobei man statt \global\def auch gleich \gdef und statt \global\edef auch gleich \xdef verwenden kann.
\protected@edef etc. sind Macros. Wenn die expandieren, steht in der Expansion nach dem \global zwar tatsächlich eines der genannten Primitiven aber das falsche. Aus
\global\protected@edef\foo{\bar}
wird bei der Expansion:
\global\let\@@protect\protect
\let\protect\@unexpandable@protect
\afterassignment\restore@protect
\edef\foo{\bar}
Du siehst, dass dann \global an der falschen Stelle steht, nämlich nicht vor dem \edef am Ende.

\protected@edef erhält bei der Definition \protect, während \edef \protect i. d. R. schlicht wegwirft, weil es normalerweise als \relax definiert sein sollte (außer ein Paket- oder Klassenautor oder ein Anwender hat mal wieder gemurkst und \protect umdefiniert, ohne es anschließend wieder korrekt auf den vorherigen Wert zurück zu setzen). LaTeX-Anwender verlassen sich natürlich darauf, dass \protect wirklich hilft, wenn eine Anweisung ansonsten zerbrechen würde - auch bei mehreren Schachtelungen.

In einigen wenigen Fällen will man dann tatsächlich \edef statt \protected@edef. Darauf kommen wir dann, wenn Du mal ein Problem mit \protected@edef hast. ;-)

Achja: \protect benötigt man dann, wenn eine Anweisung ansonsten zerbricht, das heißt zu früh expandiert wird. Das ist beispielsweise bei diversen Befehlen der Fall, wenn man sie in moving arguments verwenden. Das wiederum sind Argumente, die nicht (nur) direkt von der Anweisung verarbeitet werden, der man sie übergibt, sondern von dieser weitergereicht werden. Bei Gliederungsbefehlen ist das beispielsweise das Argument, das in die aux- und von dort in die toc-Datei geschrieben und außerdem an \...mark weitergereicht wird, um von dort in den Kolumnentitel zu gelangen. \protect verhält sich je nach Kontext dabei unterschiedlich. Mal ist es ein einfaches \string, mal ein \protect\string, mal ein \noexpand, mal ein \protect\noexpand u. v. m.

Die primäre Anleitung zu vielen LaTeX-Befehlen und internen LaTeX-Befehlen findet man übrigens in source2e.pdf. Link gibt es in den wichtigen Netzdokumenten.

Benutzeravatar
iTob
Forum-Meister
Forum-Meister
Beiträge: 1221
Registriert: Mo 19. Apr 2010, 22:19
Kontaktdaten:

Beitrag von iTob »

Guten Morgen,

danke für deine Antwort, die PDF werde ich mir bei Zeiten mal zu Gemüt führen.
KOMA hat geschrieben:In einigen wenigen Fällen will man dann tatsächlich \edef statt \protected@edef. Darauf kommen wir dann, wenn Du mal ein Problem mit \protected@edef hast. ;-)
Einverstanden. Und soll das heißen, dass ich bis dahin (wenn ich Pakete bastel) immer \protected@edef verwenden kann/sollte?

Schönes Wochenende!
Tobi

Benutzeravatar
KOMA
TeX-Entwickler
TeX-Entwickler
Beiträge: 2958
Registriert: Fr 4. Jul 2008, 17:28
Kontaktdaten:

Beitrag von KOMA »

Immer dann, wenn es sein könnte, dass im Argument (also der eigentlichen Definition) ein \protect enthalten ist, solltest Du \protected@edef verwenden. In den meisten anderen Fällen schadet es nicht, wenn Du \protected@edef verwendest. Wann immer Du \edef (oder \xdef) verwendest, solltest Du Dir Gedanken darüber machen, was aus einem eventuellen \protect werden soll und ggf. \protect entsprechend konfigurieren (und danach auch wieder restaurieren). Siehe dazu source2e im Dunstkreis der Definition von \protected@edef.

Ich habe früher übrigens auch ziemlich blauäugig \edef verwendet und mir keine Gedanken darüber gemacht. Es war ein ziemlicher Kraftaufwand, bei KOMA-Script für jedes einzelne \edef zu entscheiden, ob es nicht besser ein \protected@edef sein sollte. Ich bin mir noch immer nicht sicher, dass ich alle \edef korrekt erwischt habe.

Falls Dir langweilig wird, kannst Du dann noch versuchen zu verstehen, wie \unexpanded in e-TeX funktioniert. Bei der Gelegenheit sei auch noch auf das Paket etoolbox hingewiesen.

BTW: Kein Mensch hat je behauptet, dass (La)TeX-Programmierung einfach ist. Ich kenne nur zwei Menschen persönlich, die sie wirklich beherrschen. Ich selbst werde hingegen auch immer mal wieder von einem Resultat überrascht und muss dann entweder experimentieren oder gründlich im TeXbook nachlesen.

Benutzeravatar
iTob
Forum-Meister
Forum-Meister
Beiträge: 1221
Registriert: Mo 19. Apr 2010, 22:19
Kontaktdaten:

Beitrag von iTob »

KOMA hat geschrieben:BTW: Kein Mensch hat je behauptet, dass (La)TeX-Programmierung einfach ist. Ich kenne nur zwei Menschen persönlich, die sie wirklich beherrschen. Ich selbst werde hingegen auch immer mal wieder von einem Resultat überrascht und muss dann entweder experimentieren oder gründlich im TeXbook nachlesen.
Ich ja auch nicht... aber ich bin schon sehr zufrieden, was ich bisher – auch mit des Forums Hilfe – erreicht habe :D

Viele Grüße
Tobi

Antworten