Stilfrage "command already defined"

38 views
Skip to first unread message

Ekkart Kleinod

unread,
Feb 18, 2020, 6:11:37 AM2/18/20
to
Hi Ihr,

im changes-Paket definiere ich den Befehl "\highlight", nicht sehr
originell, andere Pakete tun das (leider) auch.

Ich hab jetzt vier Möglichkeiten, die ich sehe:

1. nichts tun und die Übersetzung crashen lassen

2. prüfen, ob das Kommando bereits definiert ist, Warnung ausgeben und
mein Kommando nicht definieren

3. prüfen, ob das Kommando bereits definiert ist, Warnung ausgeben und
mein Kommando drüberdefinieren

4. prüfen, ob das Kommando bereits definiert ist, Warnung ausgeben und
mein Kommando mit einem anderen Namen definieren (z. B. \chhighlight)


Hab ich was übersehen? Welche Möglichkeit ist die
stilsicherste/bevorzugte aus Eurer Sicht?

Danke,

Gruß, Ekkart.

Axel Berger

unread,
Feb 18, 2020, 8:35:53 AM2/18/20
to
Ekkart Kleinod wrote:
> Welche Möglichkeit ist die
> stilsicherste/bevorzugte aus Eurer Sicht?

Tendenziell drei, das ist die am ehesten zu erwartende und auf jeden
Fall mit Warnung. Das hilft für die klassische Anwenderlösung, die
Reihenfolge der Pakete zu ändern.

Zusätzlich wäre es natürlich gut, einen neuen Namen parallel zu
definieren und den alten für deprecated zu erklären.

Ich erinnere mich dunkel, irgendjemand (Markus Kohm?) habe irgendwo
begonnen, eine Liste aller irgendwo definierten Commands anzulegen.


--
/¯\ No | Dipl.-Ing. F. Axel Berger Tel: +49/ 221/ 7771 8067
\ / HTML | Roald-Amundsen-Straße 2a Fax: +49/ 221/ 7771 8069
 X in | D-50829 Köln-Ossendorf http://berger-odenthal.de
/ \ Mail | -- No unannounced, large, binary attachments, please! --

Ekkart Kleinod

unread,
Feb 18, 2020, 8:47:08 AM2/18/20
to
On 18.02.2020 14:35, Axel Berger wrote:
> Ekkart Kleinod wrote:

> Tendenziell drei, das ist die am ehesten zu erwartende und auf jeden
> Fall mit Warnung. Das hilft für die klassische Anwenderlösung, die
> Reihenfolge der Pakete zu ändern.

die hatte ich innerlich ausgeschlossen :D

> Zusätzlich wäre es natürlich gut, einen neuen Namen parallel zu
> definieren und den alten für deprecated zu erklären.

ach, eigentlich bin ich damit zufrieden, das ist ja das Problem.

Danke für Deinen Input,

Gruß, Ekkart.

Ulrike Fischer

unread,
Feb 18, 2020, 9:26:31 AM2/18/20
to
Am Tue, 18 Feb 2020 12:11:34 +0100 schrieb Ekkart Kleinod:


> im changes-Paket definiere ich den Befehl "\highlight", nicht sehr
> originell, andere Pakete tun das (leider) auch.

> Hab ich was übersehen? Welche Möglichkeit ist die
> stilsicherste/bevorzugte aus Eurer Sicht?

Hängt davon ab, welches oder welche Pakete den Befehl auch
definieren. Wenn es ein Clash mit einem wichtigen Mainstream-Paket
ist, würde ich einen anderen Befehlsnamen einführen. Wenn es
irgendein altes, selten verwendetes Paket ist, dann sollte besser
der Benutzer entscheiden, wie man den Konflikt löst. Da würde ich
eher den Fehler zulassen und dokumentieren, welche Optionen es gibt
ihn zu vermeiden.

--
Ulrike Fischer
http://www.troubleshooting-tex.de/

Ekkart Kleinod

unread,
Feb 19, 2020, 3:59:57 AM2/19/20
to
On 18.02.2020 15:26, Ulrike Fischer wrote:
>
> Hängt davon ab, welches oder welche Pakete den Befehl auch
> definieren. Wenn es ein Clash mit einem wichtigen Mainstream-Paket
> ist, würde ich einen anderen Befehlsnamen einführen.

Konkret geht es um die Dokumentklasse des MDPI

<https://www.mdpi.com/>

> Wenn es
> irgendein altes, selten verwendetes Paket ist, dann sollte besser
> der Benutzer entscheiden, wie man den Konflikt löst. Da würde ich
> eher den Fehler zulassen und dokumentieren, welche Optionen es gibt
> ihn zu vermeiden.

ok, schau ich mal, was mir dazu einfällt, ich kann ja unabhängig von
meiner Lösung das MDPI mal anschreiben.

Danke,

Gruß, Ekkart.

Phillip Helbig (undress to reply)

unread,
Feb 20, 2020, 4:50:15 AM2/20/20
to
In article <r2ggp7$anb$1...@dont-email.me>, Ekkart Kleinod <ekn...@web.de>
schrieb:

> im changes-Paket definiere ich den Befehl "\highlight", nicht sehr
> originell, andere Pakete tun das (leider) auch.
>
> Ich hab jetzt vier Möglichkeiten, die ich sehe:
>
> 1. nichts tun und die Übersetzung crashen lassen

Immer schlecht.

> 2. prüfen, ob das Kommando bereits definiert ist, Warnung ausgeben und
> mein Kommando nicht definieren

Was bringt das?

> 3. prüfen, ob das Kommando bereits definiert ist, Warnung ausgeben und
> mein Kommando drüberdefinieren

Dann funktioniert das Paket nicht wie erwünscht.

> 4. prüfen, ob das Kommando bereits definiert ist, Warnung ausgeben und
> mein Kommando mit einem anderen Namen definieren (z. B. \chhighlight)

Will man immer die Warnung sehen?

Grundsätzlich überschreibt \def, also lieber \*command benutzen.

Für eigene Macros, \newcommand benutzen. Wenn es schon definiert ist,
gibt es einen Fehler, und du kannst entscheiden, was du machst. Man
kann auch \renewcommand benutzen (muss schon definiert sein), aber da
überschreibst du, was das Paket mit dem Befehl machen willst. Wenn es
(zumindest ungefähr) das gleiche ist, dann würde ich \providecommand
benutzen (wie \newcommand falls nicht definiert, sonst wird nichts
gemacht).

Was ist aber, wenn du denselben Namen benutzen willst, aber etwas ganz
anderes machen willst? Am besten dann dein Macro einen anderen Namen
geben. Problem könnte sein, wenn du ältere Texte neu kompilieren
willst: Wenn du mit dem ursprünglichen Paket, aber ohne dein altes
Macro, kompilierst, dann gibt es einen Fehler. Du musst dann den
Quelltext ändern, um den neuen Macronamen zu benutzen. Wenn du aber das
neue Paket benutzt, dann merkst du auch, wenn es einen Fehler gibt (z.B.
unterschiedliche Anzahl von Argumenten). Es kann sein, dass es ohne
Fehler durchläuft. Spätestens beim Lesen aber sollte auffallen, dass es
nicht das erwünschte Ergebnis ist, also noch einmal Quelltext ändern und
deinen neuen Namen benutzen.

Wenn du deinen eigenen Macros Namen gibst, die zwar von der Bedeutung
klar ist, aber nicht das, was man als Erstes erwartet, gibt es weniger
Probleme. Zum Beispiel: ein Paket hat

\newcommand{\journal}[1]{\emph{#1}}

Du willst aber etwas anderes mit \journal machen. Wenn dein Macro z.B.
\Journal oder \journ heißt, dann ist es unwahrscheinlicher, dass es eine
Kollision gibt.

eu_an...@web.de

unread,
Feb 21, 2020, 9:24:52 AM2/21/20
to
Ekkart Kleinod schrieb:

> im changes-Paket definiere ich den Befehl "\highlight", nicht sehr
> originell, andere Pakete tun das (leider) auch.


Option 5:

- _Interne_ Makros immer mit einem durch "@" abgetrennten Präfix
versehen, welches den Namespace für die internen Makros Deines
Paketes bildet und so beschaffen ist, dass die Wahrscheinlich-
keit, dass andere Pakete das selbe Präfix benutzen, klein ist.

- Per Paket kvoptions oder ähnliches eine Paketoption
"NamespacePrefix" definieren, die standardmäßig einen leeren
Wert hat, über die sich aber ein Namenspräfix für alle Makros
der _Benutzerebene_ Deines Paketcodes angeben lässt.

- Beim Definieren der Makros der Benutzerebene Deines Pakets erst
prüfen, ob so ein Makro bereits definiert ist.
Wenn ja, Fehlermeldung ausgeben lassen und in der Fehlermeldung
auf die Paketoption "NamespacePrefix" aufmerksam machen,
mittels derer sich das Problem beheben lässt.

- In der Dokumentation darauf aufmerksam machen, dass
Paket-Autoren, die die Benutzerebenenmakros Deines Paket nutzen,
die Benutzerebenenmakros nicht direkt aufrufen sollen, sondern
auf eine Weise, bei der das NamespacePrefix berücksichtigt wird.

Das könnte in etwa so aussehen:

Das unten folgende Demopaket UDFooBar.sty definiert per
\define@key (keyval-Syntax) eine Paketoption "NameSpacePrefix".

Wenn man diese beim Laden des Pakets nicht angibt, werden die
Makros \UserLevelMacroA und \UserLevelMacroB definiert.

Wenn man diese Paketoption angibt, zB

\usepackage[NameSpacePrefix=MYPREFIX]{UDFooBar}

, dann werden diese Makros nicht definiert, sondern stattdessen
die Makros \MYPREFIXUserLevelMacroA und \MYPREFIXUserLevelMacroB.

Interne Makros, also Makros, die der Benutzer nicht direkt
aufrufen soll, haben allesamt Namen, die mit \UDFooBar@...
beginnen.

Die Paketoption NameSpacePrefix definiert das Makro
\UDFooBar@NameSpacePrefix.

Das interne Makro \UDFooBar@NameSpacePrefix hält also das
Namenspräfix für die Makros der Benutzerebene.

Die Kontrollwort-Token, die für die Makros der Benutzerebene
stehen, können durch

\csname\UDFooBar@NameSpacePrefix...\endcsname

gebildet werden.

Also zB

\csname\UDFooBar@NameSpacePrefix UserLevelMacroA\endcsname

und

\csname\UDFooBar@NameSpacePrefix UserLevelMacroB\endcsname

. Angenommen, das Namenspräfix ist leer/\UDFooBar@NameSpacePrefix
ist leer definiert.

Dann ergeben die \csname..\endcsname-Konstrukte die Kontrollwort-
Token

\UserLevelMacroA und \UserLevelMacroB.

Angenommen, das Namenspräfix/das Makro \UDFooBar@NameSpacePrefix
ist so definiert, dass es zu der Phrasse "MYPREFIX" expandiert.

Dann ergeben die \csname..\endcsname-Konstrukte die Kontrollwort-
Token

\MYPREFIXUserLevelMacroA und \MYPREFIXUserLevelMacroB.

Wenn man das entsprechende Kontrollwort-Token per \newcommand
als Makro definieren möchte, muss man es erst aus dem
\csname..\endcsname-Konstrukt bilden lassen, bevor man
\newcommand darauf loslassen kann.

Das könnte so aussehen:

\expandafter\newcommand
\csname\UDFooBar@NameSpacePrefix UserLevelMacroA\endcsname[1]{...}

Auf Dauer nerven solche \expandafter-Orgien aber.

Deshalb ist noch das Makro \UDFooBar@Name definiert, welches so
funktioniert:

\UDFooBar@Name<Zeug ohne geschweifte Klammern>{<MakronameOhnePräfix>}
->
<Zeug ohne geschweifte Klammern>\NameSpacePrefixMakronameOhnePräfix

<Zeug ohne geschweifte Klammern> kann auch leer sein.

\UDFooBar@Name bastelt also aus einem in Klammern
eingeschachtelten Makro-Namen ohne Präfix das entsprechende
Kontrollwort-Token mit Präfix.

Angenommen, das Namenspräfix/das Makro \UDFooBar@NameSpacePrefix
ist so definiert, dass es zu der Phrasse "MYPREFIX" expandiert.

\UDFooBar@Name\newcommand{UserLevelMacroA}...
wird dann zu:
\newcommand\MYPREFIXUserLevelMacroA...

\UDFooBar@Name{UserLevelMacroA}
wird dann zu:
\MYPREFIXUserLevelMacroA

\UDFooBar@Name\show{UserLevelMacroA}
wird dann zu:
\show\MYPREFIXUserLevelMacroA

\UDFooBar@Name\UDFooBar@Name\global\let{UserLevelMacroA}={UserLevelMacroB}
wird dann zu
\UDFooBar@Name\global\let\MYPREFIXUserLevelMacroA={UserLevelMacroB}
wird dann zu
\global\let\MYPREFIXUserLevelMacroA=\MYPREFIXUserLevelMacroB

Damit man es mit den Fehlermeldungen, falls ein bereits
definiertes Benutzerebenen-Makro nochmal definiert werden soll,
leichter hat, ist auch noch ein internes Makro

\UDFooBar@ifdefinable{<NameDesUserLevelMakro>}{<code>}

definiert.

Wenn \MYPREFIXNameDesUserLevelMakro bereits (zB durch ein anderes
Paket) definiert ist, bekommt man eine Fehlermeldung und den
Hinweis, dass man den Name-Clash beheben kann, wenn man das Paket
UDFooBar mit einer anderen Präfix-Angabe in der Paketoption

NameSpacePrefix=...

lädt.

Wenn \MYPREFIXNameDesUserLevelMakro nicht definiert ist, wird
<code> ausgeführt.


Hier das Demo-Paket UDFooBar.sty:


\NeedsTeXFormat{LaTeX2e}[2005/12/01]
\ProvidesPackage{UDFooBar}[2020/02/21 0.00beta1 Demo Package for Namespace-Prefix]
\RequirePackage{kvoptions}
%%--------------------------------------------
%% The hardcoded prefix for all internal macros is "UDFooBar@".
%%--------------------------------------------
%% Namespace-Management for all userlevel-macros:
%%
%% The macro which holds the namespace-prefix for all userlevel-macros:
\newcommand\UDFooBar@NameSpacePrefix{}
%%--------------------------------------------
%% \UDFooBar@Name<stuff without braces>{<MacroName>}
%% ->
%% <stuff without braces>\<\UDFooBar@NameSpacePrefix><MacroName>
%% (In expansion contexts \UDFooBar@Name requires two "hits"
%% by \expandafter/two expansion-steps to deliver the result.)
%--------------------------------------------
\@ifdefinable\UDFooBar@Name{%
\long\def\UDFooBar@Name#1#{\romannumeral0\UDFooBar@Innername{#1}}%
}%
\newcommand\UDFooBar@Innername[2]{%
\expandafter\UDFooBar@Exchange
\expandafter{\csname\UDFooBar@NameSpacePrefix#2\endcsname}{ #1}%
}%
\newcommand\UDFooBar@Exchange[2]{#2#1}%
%%--------------------------------------------
%% \UDFooBar@ifdefinable{<macroname>}{<Code>}
%% Checks whether a control sequence whose name is formed by
%% \UDFooBar@NameSpacePrefix<macroname>
%% is definable.
%% If so, exexutes code.
%% Otherwise raises an error-message.
%%--------------------------------------------
\newcommand\UDFooBar@ifdefinable[1]{%
\UDFooBar@Name\UDFooBar@@ifdefinable{#1}%
}%
\newcommand\UDFooBar@@ifdefinable[2]{%
\edef\reserved@a{\expandafter\@gobble\string#1}%
\@ifundefined\reserved@a{%
\edef\reserved@b{\expandafter\@carcube\reserved@a xxx\@nil}%
\ifx\reserved@b\@qend\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{\@firstoftwo}{%
\ifx\reserved@a\@qrelax\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
}%
}{\@firstoftwo}%
{\UDFooBar@notdefinable}{#2}%
}%
\newcommand\UDFooBar@notdefinable{%
\PackageError{UDFooBar}{%
Currently NameSpacePrefix=`\UDFooBar@NameSpacePrefix' is specified.\MessageBreak
Command \@backslashchar\reserved@a\space already defined.\MessageBreak
Or name \@backslashchar \@qend ... illegal.\MessageBreak
Try specifying a suitable prefix for the\MessageBreak
name-space of the user-macros%
}{%
Try specifying a suitable prefix for the name-space of the\MessageBreak
user-macros of this package via the package-option\MessageBreak
\space\space NameSpacePrefix=<Prefix>\MessageBreak
(Make sure the <Prefix> is not `end' because commands beginning\MessageBreak
with `\@backslashchar\@qend...' are illegal in LaTeX.)%
}%
}%
%%--------------------------------------------
%% The kv-option "NameSpacePrefix":
%%--------------------------------------------
\define@key{UDFooBar}{NameSpacePrefix}{%
\gdef\UDFooBar@NameSpacePrefix{#1}%
\@onelevel@sanitize\UDFooBar@NameSpacePrefix
\ifx\UDFooBar@NameSpacePrefix\@qend
\PackageError{UDFooBar}{%
Name-space-prefix `end' cannot be specified\MessageBreak
and therefore is ignored.\MessageBreak
As default no prefix is used%
}{%
Try specifying a suitable prefix for the name-space of the\MessageBreak
user-macros of this package via the package-option\MessageBreak
\space\space NameSpacePrefix=<Prefix>\MessageBreak
(Make sure the <Prefix> is not `end' because commands beginning\MessageBreak
with `\@backslashchar\@qend...' are illegal in LaTeX.)%
}%
\gdef\UDFooBar@NameSpacePrefix{}%
\fi
}%
\ProcessKeyvalOptions {UDFooBar}

%% Now define all user-level-macros in terms of \UDFooBar@notdefinable
%% and \UDFooBar@Name:

\UDFooBar@ifdefinable{UserLevelMacroA}{%
\UDFooBar@Name\newcommand{UserLevelMacroA}[1]{%
This is the argument of the UDFooBar-package's UserLevelMacroA: #1.%
}%
}%
\UDFooBar@ifdefinable{UserLevelMacroB}{%
\UDFooBar@Name\newcommand{UserLevelMacroB}[1]{%
This is the argument of the UDFooBar-package's UserLevelMacroB: #1.%
}%
}%
%%
%% Note to package programmers:
%% ----------------------------
%%
%% In your packages do never call the user-level-macros of this
%% package directly!
%% Call them via \UDFooBar@Name or via \csname..\endcsname!
%%
%% E.g., do
%%
%% \UDFooBar@Name{UserLevelMacroA}{<Argument>}
%%
%% or
%%
%% \csname\UDFooBar@NameSpacePrefix UserLevelMacroA\endcsname{<Argument>}
%%
%% instead of
%%
%% \UserLevelMacroA{<Argument>}
%%
%% !!! When doing this, be careful about the order in time in which things
%% take place when applying \uppercase/\lowercase and the like !!!
%%
\endinput
% End of UDFooBar.sty


Wenn kein anderes zuvor geladenes Paket eines der Makros
\UserLevelMacroA und \UserLevelMacroB definiert, kann man das
Paket UDFooBar.sty ohne Paket-Optionen laden und bekommt keine
Fehlermeldungen und kann die Makros \UserLevelMacroA und
\UserLevelMacroB verwenden:


\documentclass{article}

\usepackage{UDFooBar}

\begin{document}

\UserLevelMacroA{Argument}

\UserLevelMacroB{Argument}

\end{document}


Angenommen, eines der Makros \UserLevelMacroA / \UserLevelMacroB
ist beim Laden von UDFooBar.sty bereits (durch ein anderes Paket)
definiert.

Dann bekommt man eine nette Fehlermeldung und den Hinweis, dass
man beim Laden von UDFooBar.sty die Paketoption
NameSpacePrefix=...
verwenden kann, um das Problem zu beheben:


\documentclass{article}

\newcommand\UserLevelMacroA{This macro is already defined.}

\usepackage{UDFooBar}

\begin{document}

\UserLevelMacroA{Argument}

\UserLevelMacroB{Argument}

\end{document}


Wenn man das dann tut, werden die Namen der von UDFooBar.sty
definierten Benutzerebenen-Makros allesamt mit einem Präfix
versehen und man kann die bereits von anderen Paketen definierten
Benutzerebenen-Makros unter dem alten Namen weiterbenutzen und
hat die von UDFooBar.sty definierten Benutzerebenen-Makros unter
Makronamen zur Verfügung, die noch das zusätzliche Präfix haben:


\documentclass{article}

\newcommand\UserLevelMacroA{This macro is already defined.}

\usepackage[NameSpacePrefix=MYPREFIX]{UDFooBar}

\begin{document}

\UserLevelMacroA

\MYPREFIXUserLevelMacroA{Argument}

\MYPREFIXUserLevelMacroB{Argument}

\end{document}



Ulrich

Peter Flynn

unread,
Jul 9, 2022, 9:14:04 AMJul 9
to
On 08/07/2022 22:23, in comp.text.tex Ulrich D i e z wrote:
[snip]
> [...]at de.comp.tex.tex a discussion took place in February 2020:
> Stilfrage "command already defined"
> URL <https://groups.google.com/g/de.comp.text.tex/c/-q-TGo8chbc/m/nbHGwcumBQAJ>

[I have translated a little of this and set the References to include
the original thread.]

An interesting thread on what to do with command-name conflicts when
writing a package, suggesting four possibilities:

On 18/02/2020 11:11, Ekkart Kleinod wrote:

> 1. do nothing and let it crash
>
> 2. see if the command is already defined, issue a warning, and don't
> define my command
>
> 3. see if the command is already defined, issue a warning, and overwrite
> it with my command
>
> 4. see if the command is already defined, issue a warning, and pick
> another name for my command

The thread ends with a good summary of the internal vs external naming
options:

On 21/02/2020 14:24, eu_an...@web.de wrote:

> Option 5
>
> - _Internal_ macros: always use a prefix separated by "@", which
> establishes a namespace for the internal macros of your package,
> and chosen to reduce the chances another package using the same
> prefix.
>
> - use kvoptions or similar to provide a package option
> "NamespacePrefix" which is null by default, but provides user
> control over the naming prefix for the user-level commands of
> your package.
>
> - when defining user-level commands in your package, first check
> to see if such a macro is already defined [elsewhere]. If yes,
> issue an error message and draw attention to the NamespacePrefix
> option that will resolve the problem.
>
> - In documentation, make it clear that package authors who use the
> user-level commands of your package should not call those
> commands direct, but using a method that takes the
> NamespacePrefix into consideration.

[followed by an extensive worked example].

On 18/02/2020 13:35, Axel Berger wrote:

> I seem to remember that someone (Markus Kohm), somewhere, made a
> start on a list of all commands defined somewhere.
Does anyone know if this is ongoing?

Peter

Ulrich D i e z

unread,
Jul 9, 2022, 6:29:54 PMJul 9
to
Peter Flynn wrote:

> On 18/02/2020 13:35, Axel Berger wrote:
>
>> I seem to remember that someone (Markus Kohm), somewhere, made a
>> start on a list of all commands defined somewhere.
> Does anyone know if this is ongoing?

There seems to be a perl-script available at
<https://komascript.de/texcommands>
--the site is written in German language--which searches the
latex- and the generic-branch of a TeX Live Installation and
creates a database which lists in which files definitions of
which commands can be found.

I did not test it. ;-)

Sincerely

Ulrich
Reply all
Reply to author
Forward
0 new messages