Meine letzten beiden Fragen konnten gelöst werden. Allerdings gibt es jetzt wieder Probleme bei Labels und Referenzen darauf. Diese konnte ich mit den bisherigen Lösungen nicht beheben. Deshalb meine Frage, ob es eine grundsätzliche Verfahrensweise gibt, wie man pgfoo-Methoden aufrufen kann, damit sie auch innerhalb von anderen Macros funktionieren? Oder gibt es da einfach kein Allheilmittel und muss von Fall zu Fall unterschiedlich betrachtet werden? Hier mal ein Beispiel, auf das ich jetzt gestoßen bin:

Open in writeLaTeX
\documentclass{scrartcl}
\usepackage[utf8]{inputenc}
\usepackage{pgf}
\usepgfmodule{oo}

\pgfooclass{MyClass}{
\attribute name;
\method MyClass(#1){ % constructor
    \pgfooset{name}{#1} 
}
\method printName() {
    \pgfoovalueof{name}
}
\method getId() {label1}
}

\pgfoonew \myObject=new MyClass(EinName)

\begin{document}
\myObject.printName()

\section{Section}
\label{\myObject.getId()}
Lorem

\section{Another section}
Ipsum \ref{\myObject.getId()}.

\end{document}

Gibt es eine Lösung das zu beheben? Gibt es eine Möglichkeit derartige Fehler endgültig zu vermeiden?

gefragt 06 Aug '14, 16:50

ErnstZ's gravatar image

ErnstZ
611132833
Akzeptiert-Rate: 62%

Das ist das gleiche Problem wie bei Deiner letzten Frage, was man daran merkt, dass die Fehlermeldung die gleiche ist.

(06 Aug '14, 16:53) cgnieder

korrekt, allerdings bleibt die Fehlermeldung, wenn ich es so versuche zu lösen wie bei meinem letzten Problem

(06 Aug '14, 16:54) ErnstZ

Naja, letztlich willst Du ja, dass das Äquivalent von \label{label1} und \ref{label1} passiert, richtig? Dann solltest Du durch Expansion auch dafür sorgen, dass das, was \label und \ref zu sehen bekommen, tatsächlich label1 ist und nicht ein Makro, das irgendwann irgendwie dahin kommt.

(06 Aug '14, 16:56) cgnieder

Vielleicht wäre ja etwas wie \myObject.setReference() und \myObject.getReference(), die intern dann \label und \ref benutzen, eine Variante für Dich.

(06 Aug '14, 16:59) cgnieder

zu deinem ersten Kommentar: richtig, kann man denn die Expansion irgendwie anstoßen?

zum zweiten Kommentar: sowas ginge, allerdings war meine Idee, einfach nur das Label zurückzugebe, da es unterschiedlich referenziert werden könnte (bspw. pageref) und ich vermeiden wollte, für jede Art der Referenzierung eine Methode zu definieren. Aber das wäre in der Tat eine Möglichkeit.

(06 Aug '14, 17:12) ErnstZ

Grundsätzlich: Wenn etwas in eine Datei geschrieben werden soll (und das ist bei \label definitiv der Fall), dann muss das vollständig expandierbar sein! Siehe dazu auch das Thema expansion.

(06 Aug '14, 17:21) gast3

Mir ist ja nicht so recht klar, wie du mit deiner Methode unterschiedliche Labels erzeugen willst. Abgesehen davon: Wenn ich das richtig sehe, wurde pgfoo entwickelt um komplizierte tikz-Objekte zu "malen". Wenn du das dort verwenden willst, wo expandiert wird, dann musst du die Ausgabe/den "Returnwert" in einem Befehl speichern defreturn{label1) und dann nach Aufruf der Methode label{return} benutzen.

(06 Aug '14, 19:01) Ulrike Fischer

Obiges Beispiel erzeugt natürlich keine unterschiedlichen Labels. Das Beispiel ist nur eine Abstraktion meines eigentlichen Dokuments. Es sollte nur zeigen, was das Problem ist. Ich glaube Minimalbeispiel sagt man dazu ;)

(07 Aug '14, 13:06) ErnstZ
Ergebnis 5 von 8 show 3 more comments

Das objektorientierte Prinzip funktioniert umso besser, je konsequenter man es anwendet. In diesem Fall besteht die Konsequenz darin, nicht das Attribut nach außen zu reichen, sondern eine Methode anzubieten, um auf dem Attribut zu operieren:

Open in writeLaTeX
\documentclass{scrartcl}
\usepackage[utf8]{inputenc}
\usepackage{pgf}
\usepgfmodule{oo}

\pgfooclass{MyClass}{
\attribute name;
\attribute id;
\method MyClass(#1){ % constructor
    \pgfooset{name}{#1}%
    \pgfooset{id}{\detokenize{#1}}%
}
\method printName() {%
    \pgfoovalueof{name}%
}
\method IdOperation(#1){%
    \begingroup
       \pgfooget{id}{\temporaryidvalue}%
       \edef\temporaryaction{\noexpand\endgroup\noexpand#1{\temporaryidvalue}}%
    \temporaryaction
}
}

\pgfoonew \myObject=new MyClass(EinName)

\begin{document}
\myObject.printName()

\section{Section}
\myObject.IdOperation(\label)
Lorem

\section{Another section}
Ipsum \myObject.IdOperation(\ref).

\end{document}

Noch konsequenter ist es, nur bestimmte Operationen zuzulassen und für jede einzelne dieser Operationen einzelne Methoden zur Verfügung zu stellen:

Open in writeLaTeX
\documentclass{scrartcl}
\usepackage[utf8]{inputenc}
\usepackage{pgf}
\usepgfmodule{oo}

\pgfooclass{MyClass}{
\attribute name;
\method MyClass(#1){ % constructor
    \pgfooset{name}{#1}%
    \pgfooset{label}{\detokenize{#1}}%
}
\method printName() {%
    \pgfoovalueof{name}%
}
\method set label(#1){%
    \begingroup
       \pgfoothis.get id(\temporaryidvalue)%
       \edef\temporaryaction{%
         \noexpand\endgroup\noexpand\label{objectid.\temporaryidvalue}}%
    \temporaryaction
}
\method show reference(){%
    \begingroup
       \pgfoothis.get id(\temporaryidvalue)%
       \edef\temporaryaction{%
         \noexpand\endgroup\noexpand\ref{objectid.\temporaryidvalue}}%
    \temporaryaction
}
\method show page reference(){%
    \begingroup
       \pgfoothis.get id(\temporaryidvalue)%
       \edef\temporaryaction{%
         \noexpand\endgroup\noexpand\pageref{objectid.\temporaryidvalue}}%
    \temporaryaction
}
}

\pgfoonew \myObject=new MyClass(EinName)

\begin{document}
\myObject.printName()

\section{Section}
\myObject.set label()
Lorem

\section{Another section}
Ipsum \myObject.show reference().

\end{document}

Dabei mache ich mir auch gleich zu Nutze, dass pgf für jedes Objekt selbst bereits eine eindeutige Id erzeugt, die zufällig für Labels verwendbar ist. Man könnte das ggf. auch mit einem zusätzlichen \detokenize absichern. Notwendig ist das aber nicht.

Noch schöner wäre, wenn pgf auch private Methoden bieten würde. Dann könnte man IdOperation als private Operation anbieten und die drei Methoden show reference, show page reference und set label darauf aufbauend definieren.

Permanenter link

beantwortet 07 Aug '14, 13:25

gast3's gravatar image

gast3
(ausgesetzt)
Akzeptiert-Rate: 53%

bearbeitet 07 Aug '14, 14:05

Sehr gut Ijon. Gefällt mir richtig gut mit deinem generischen Makro-Dispatch deines ersten Vorschlages. Zur besseren Kontrolle ist dann Variante 2 zu bevorzugen. Ich persönlich nehme jetzt doch das Merge aus beiden und die Verwendung von IdOperation(#1) als Delegatee.

Bzgl. privater Methoden kann man das so lösen, dass diese einen möglichst komplizierten Namen bekommen, an den man sich bei vermeintlicher Verwendung nicht erinnern kann ;)

(07 Aug '14, 14:08) ErnstZ

Was Du ja willst, ist ein return wert - und den willst Du geeignet weiter verwenden.

Nun gibt es in TeX zwei grundlegend und systematisch verschiedene Konzepte, die tief in der Natur von TeX wurzeln: Expansion und Ausfuehrung. Die genauen Details zu kennen ist notwendig, um das richtig zu verstehen. Wenn Du Dich dafuer interessierst: ich habe zu dem Thema mal auf tex.sx einiges geschrieben, vergleiche https://tex.stackexchange.com/questions/12668/where-do-i-start-latex-programming/27589#27589 . Das diskutiert dieses Thema ausfuehrlich, dann wird auch vieles klarer ueber TeX-Programmierung (und nichts anderes tust Du ja hier).

Um in dem Sprech weiterzumachen kann ich nur die Kommentare der anderen wiederholen: \myobject.getId() ist nicht expandierbar, sondern es ist ausfuehrbar. Du fragtest nach einer "generellen Moeglichkeit, so etwas zu vermeiden". Die gibt es: geh' im Zweifelsfall davon aus, dass Makros von nicht-eigenem Code ausfuehrbar - und nicht expandierbar - sind. Es sei denn, sie sind explizit als expandierbar markiert.

In der Konsequenz heisst dass, dass Deine Methoden den gewuenschten Wert in ein Makro schreiben muessen. Das koennte im einfachsten Fall ein fixer Makro-Name der Art \pgretval sein:

Open in writeLaTeX
\documentclass{scrartcl}
\usepackage[utf8]{inputenc}
\usepackage{pgf}
\usepgfmodule{oo}

\pgfooclass{MyClass}{
\attribute name;
\method MyClass(#1){ % constructor
    \pgfooset{name}{#1} 
}
\method printName() {
    \pgfoovalueof{name}
}
\method getId() {\def\pgfretval{label1}}
}

\pgfoonew \myObject=new MyClass(EinName)

\begin{document}
\myObject.printName()

\section{Section}

\myObject.getId()%
\label{\pgfretval}
Lorem

\section{Another section}
\myObject.getId()%
Ipsum \ref{\pgfretval}.

\end{document}

Wie das geaenderte Beispiel zeigt, weist \myObject.getId() den gewuenschten Wert einem Makro zu. Das wiederum ist expandierbar und kann auch als solches verwendet werden.

Dieses Idiom ist generall verwendbar und funktioniert meistens bei sowas.

Damit kommst Du sicher weiter, was die Nutzung von pgfoo angehet. Ich empfehle Dir die Lektuere des oben genannten Links, falls Du ein "Aha Erlebnis" suchst.

Permanenter link

beantwortet 06 Aug '14, 22:50

cfeuersaenger's gravatar image

cfeuersaenger
3.7k23
Akzeptiert-Rate: 34%

bearbeitet 06 Aug '14, 23:32

cgnieder's gravatar image

cgnieder
22.1k253463

Danke dir erstmal für die ausführliche Erklärung. Deinen Link werde ich mir auf jeden Fall zu Gemüte führen. Ein Problem mit der Lösung habe ich allerdings noch. Im Sinne der Objektorientierung (OO) gefällt es mir gar nicht, dass eine "globale Variable" (\pgfretval) als so eine Art Klassenvariable (statische Variable) verwendet wird. Die teilen sich alle Instanzen der Klasse MyClass. Gut, Nebenläufigkeit bei TeX-Dokumenten ist natürlich kein Thema, aber sauber im Sinne von OO ist das leider nicht.

(07 Aug '14, 09:10) ErnstZ

Till Thantaus Versuch, OO-Konzepte in LaTeX verfügbar zu machen, ist auf jeden Fall sehr löblich und meinerseits sehr willkommen. Allerdings gibt's da Grenzen die TeX geschuldet sind.

(07 Aug '14, 09:11) ErnstZ
1

Ich stimme Dir in beiden Kommentaren zu. Eine Alternative, die Till Tantau in seinem Manual selber anspricht, ist: uebergebe den Namen des Ausgabemakros an die Methode. Also sowas wie \method getId(#1) {\def#1{label1}} .

(07 Aug '14, 09:49) cfeuersaenger

Ich habe selbe auch einige Erfahrung mit LaTeX gesammelt - sowohl mit "uebergebe Namen des Ausgabemakros" als auch "weise immer derselben Variable zu" (sowohl global als auch lokal) als auch "expansion vs execute". Meiner Erfahrung nach ist "weise Resultate immer (lokal) derselben Variable wie \pgfretval zu" die einfachste und sauberste. Beachte: das ist NICHT global, sondern lokal! Die Zuweisung gilt nur bis zum naechsten \endgroup oder }.

(07 Aug '14, 09:50) cfeuersaenger

Tadaaa, das ist die Lösung :) Das ist dann quasi eine Methode mit Rückgabewert. Somit geht's doch und damit wär ich auch zufrieden.

(07 Aug '14, 09:51) ErnstZ
1

@Christian: habe mir gerade dein "Notes on Programming in TeX" durchgelesen. Super Einführung! Danke dafür. Mir ist nun Einiges klarer. Definitiv ein Aha-Erlebnis ;)

(07 Aug '14, 12:03) ErnstZ
Ergebnis 5 von 6 show 1 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:

×32
×27
×6
×3

gestellte Frage: 06 Aug '14, 16:50

Frage wurde gesehen: 10,487 Mal

zuletzt geändert: 07 Aug '14, 14:08