3

To re-define a command to contain itself (patching in TeX parlance) you usually use \let. This answer by @egreg says:

Never use \let on commands defined with \DeclareRobustCommand or commands defined with \newcommand and having an optional argument.

So a natural question is what should we do in such cases?

For example, how do I re-define \bibitem to add another command after it? This:

\let\old@bibitem\bibitem
\def\bibitem{\old@bibitem\it}

does not work, and \show\bibitem shows why:

> \bibitem=macro:
->\@ifnextchar [\@lbibitem \@bibitem .

What should I do to achieve the effect?

I would prefer not to use packages such as xpatch because I am modifying a class which others will use, and I try to use as few pacages as possible to minimize possible conflicts.

  • In this case find the source and reuse it. – touhami Sep 26 '15 at 21:46
  • 1
    \LetLtxMacro from the package with the same name – user31729 Sep 26 '15 at 21:47
  • @touhami Do you mean I should use show and copy the modified contens? In this case, I should modify \@lbibitem and \@bibitem, right? This is not robust as to future changes or may not be compatible with other packages, no? – Alexander Gelbukh Sep 26 '15 at 21:49
  • If you want robust patching, use one of the packages for that (etoolbox, xpatch, letltxmacro, etc.). In my view it is foolish to make a class load tcolorbox (say, which is a great package), but not so when it is a utility/programming package. Such utility packages are likely already getting loaded behind the scenes anyway (letltxmacro loads etoolbox, e.g.; so do many other packages nowadays). On the other hand, you seem to be asking for "high-level" and "generic" solutions for a very "general" question; in some ways these are in conflict with one another. – jon Sep 26 '15 at 21:57
  • 1
    You simply have to go deeper into the definitions; if the aim is to print the citation label in italics, patching \bibitem is surely the wrong choice independently of any package you may load. – egreg Sep 26 '15 at 21:58
6

The command \bibitem has no argument, much less an optional one. The commands I refer to in the quoted part of my answer are those defined with

\newcommand{<macro>}[<args>][<default>]{...}

not others defined in an indirect way with \@ifnextchar or \@ifstar like \bibitem or \section.

If your aim is to print the citation label in italics, patching \bibitem is the wrong choice independently of any package such as etoolbox, xpatch or letltxmacro you load.

What could you do? Let's see: \bibitem has the definition you showed, so we know we have to patch either \@lbibitem or \@bibitem.

Using texdef we see

> texdef -t latex -s @lbibitem
% latex.ltx, line 6228:
\def\@lbibitem[#1]#2{\item[\@biblabel{#1}\hfill]\if@filesw
      {\let\protect\noexpand
       \immediate
       \write\@auxout{\string\bibcite{#2}{#1}}}\fi\ignorespaces}

> texdef -t latex -s @bibitem
% latex.ltx, line 6232:
\def\@bibitem#1{\item\if@filesw \immediate\write\@auxout
       {\string\bibcite{#1}{\the\value{\@listctr}}}\fi\ignorespaces}

Well. There are two cases: if \bibitem is followed by [, we need to see how \@biblabel is defined and we see

> texdef -t latex -s @biblabel
% latex.ltx, line 6278:
\def\@biblabel#1{[#1]}

so we just need to do

\def\@biblabel#1{[\textit{#1}]}

If there is no optional argument, we need to see how the standard label of the enumerate environment started with \begin{thebibliography} is defined. Very well:

> texdef -t latex -s thebibliography
% article.cls, line 575:
\newenvironment{thebibliography}[1]
     {\section*{\refname}%
      \@mkboth{\MakeUppercase\refname}{\MakeUppercase\refname}%
      \list{\@biblabel{\@arabic\c@enumiv}}%
           {\settowidth\labelwidth{\@biblabel{#1}}%
            \leftmargin\labelwidth
            \advance\leftmargin\labelsep
            \@openbib@code
            \usecounter{enumiv}%
            \let\p@enumiv\@empty
            \renewcommand\theenumiv{\@arabic\c@enumiv}}%
      \sloppy
      \clubpenalty4000
      \@clubpenalty \clubpenalty
      \widowpenalty4000%
      \sfcode`\.\@m}
     {\def\@noitemerr
       {\@latex@warning{Empty `thebibliography' environment}}%
      \endlist}

Hmm, this depends on the class; let's assume the class is article. Fine! The label is still printed using \@biblabel, so the above trick is good in both cases.

So your task is just adding

\def\@biblabel#1{[\textit{#1}]}

to your personal style file; if the patch must be done in the document preamble, ensure to add the line between \makeatletter and \makeatother (see What do \makeatletter and \makeatother do?). However this might depend on the class, but usually one can count on the fact that \@biblabel is what's to be changed.

No, patching commands is definitely not easy.

  • Thank you! By now I've solved my problem in a less elegant (but trivial) way. My intention was, roughly (not exactly) to print references, but not labels and not the word "References", in grey color, so a trivial idea was to redefine \bibitem[x]{y} as \color{black}\bibitem[x]{y}\color{gray}, and yes, I was looking for an easy and generic way. What I learnt from your answer is that it is considered valid to rely on how a command is defined -- when you say "it depends on the class" -- because there is no easy and generic way. – Alexander Gelbukh Sep 26 '15 at 23:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.