9

I often use short macros in mathematical formulas for frequently used symbols, e.g. \d x for a differential dx or, say, \v if I need a vector v very often in my text to make things more readable. However, I get a clash with predefined macros because \d stands for a dot under the next character and v for the hacek accent, which I don't want to override (maybe I need them in the bibliography...).

So, I came up with the following to override those macros only in math mode:

\documentclass{article}

\usepackage{everyhook}
\newcommand{\mathdef}[2]{%
  \PushPostHook{math}{\expandafter\def\csname #1\endcsname{#2}}%
  \PushPostHook{display}{\expandafter\def\csname #1\endcsname{#2}}}
\mathdef{d}{\mathrm{d}}%

\begin{document}
  \d x  is an x with a dot below and $\int f(x) \d x$ is an integral over $x$.
\end{document}

However, I would like the command to be defined like normal macros too, i.e. \mathdef{\d}{\mathrm{d}}, and also be able to take arguments, but all my experiments with expandafter, unexpanded, etc. didn't work out and led only to the usual strange error messages. Any hint how I can do that?

Furthermore, do you think there is a big performance penalty using \everymath like that in a large document?

  • 2
    You can just use #1 for the macro: \newcommand{\mathdef}[2]{% \PushPostHook{math}{\def#1{#2}}% \PushPostHook{display}{\def#1{#2}}} and then use \mathdef{\d}{\mathrm{d}}, it is not required to use \csname here. – Martin Scharrer Mar 1 at 12:05
  • 1
    Of course the easiest way to avoid problems is to choose different macro names, e.g., \md for a differential. Or, especially for short substitutions, don't use macros at all, because they make the text less readable, for example \vec v or \vec{v} are immediately clear to yourself and possibly others, while for \v you need to remember or look up the definition somewhere - and it is not that much extra typing. – Marijn Mar 1 at 12:13
  • @MartinScharrer Yes, you're right. Probably I had another error in my original document and drew the wrong conclusions... – Elmar Zander Mar 4 at 9:22
  • @Marijn I know, but I do not want that. First, \md for the differential is not really mnemonic, and maybe trying to do this in a consistent way, you run into other clashes. Second, writing explicitly \vec v and stuff like that is usually ok for short documents (and I do that myself), but for longer ones and long formulas it can become cumbersome. Sometimes, you don't see the formula anymore for all the \vecs, \mathbbs, \mathcals and so on, and I also find it annoying when I want to put the variable into a sub- or superscript and I always have to enclose it in curly braces. – Elmar Zander Mar 4 at 9:32
  • In the orthogonal direction to Martin's suggestion, I rename some of the “accent” commands to use them for math instead. For instance \let\Hungarumlaut\H\renewcommand{\H}{\mathcal{H}} My thinking is that I don't use the Hungarumlaut that much, so it isn't too much of an inconvenience to type Erd\Hungarumlaut os – Matthew Leingang Mar 5 at 17:51
5

My idea is very similar to egreg's, but I'd like to add an optional argument, so the math command could process arguments itself. The code:

\documentclass{article}

\usepackage{xparse}
\DeclareDocumentCommand{\mathdef}{mO{0}m}{%
  \expandafter\let\csname old\string#1\endcsname=#1
  \expandafter\newcommand\csname new\string#1\endcsname[#2]{#3}
  \DeclareRobustCommand#1{%
    \ifmmode
      \expandafter\let\expandafter\next\csname new\string#1\endcsname
    \else
      \expandafter\let\expandafter\next\csname old\string#1\endcsname
    \fi
    \next
  }%
}

\mathdef{\v}[1]{\tilde{#1}}
\mathdef{\d}{\mathrm{d}}

\begin{document}
Ha\v{c}ek and tilde $\v{a}+\v{b}=1$.

\d x  is an x with a dot below and $\int f(x) \d x$ is an integral over $x$.
\end{document}

The result:

enter image description here

  • Would you try $\begin{array}{c}\v{a}\end{array}$? – egreg Mar 4 at 11:49
  • @egreg: You're right. It fails horribly. I've replaced \renewcommand by \DeclareRobustCommand which seems to fix it. Thank you for pointing out. – Sergei Golovan Mar 4 at 15:10
6

I would not use \everymath.

\documentclass{article}
\usepackage{letltxmacro}

\makeatletter
\newcommand{\mathdef}[2]{%
  \@ifundefined{#1}{\@mathdef@new{#1}{#2}}{\@mathdef@remember{#1}{#2}}
}

\newcommand{\@mathdef@remember}[2]{%
  \expandafter\LetLtxMacro
    \csname textmode@#1\expandafter\endcsname
    \csname #1\endcsname
  \expandafter\def\csname mathmode@#1\endcsname{#2}%
  \expandafter\DeclareRobustCommand\csname#1\endcsname{%
    \ifmmode\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
     {\csname mathmode@#1\endcsname}{\csname textmode@#1\endcsname}%
  }%
}
\newcommand{\@mathdef@new}[2]{%
  \expandafter\DeclareRobustCommand\csname#1\endcsname{#2}%
}
\makeatother

\mathdef{d}{\mathop{}\!\mathrm{d}}

\begin{document}

\d{x} is an x with a dot below and $\int f(x) \d x$ is an integral over $x$.

\end{document}

enter image description here

I don't think this is a good way to go, though. It's confusing and prone to errors.

See When to use \LetLtxMacro? for information about \LetLtxMacro.

It's a bit easier with etoolbox:

\documentclass{article}
\usepackage{etoolbox}

\makeatletter
\newcommand{\mathdef}[2]{%
  \@ifundefined{#1}{\@mathdef@new{#1}{#2}}{\@mathdef@remember{#1}{#2}}
}

\newcommand{\@mathdef@remember}[2]{%
  \expandafter\robustify\csname#1\endcsname
  \csletcs{textmode@#1}{#1}%
  \csdef{mathmode@#1}{#2}%
  \protected\csdef{#1}{%
    \ifmmode\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
     {\csuse{mathmode@#1}}{\csuse{textmode@#1}}%
  }%
}
\newcommand{\@mathdef@new}[2]{%
  \protected\csdef{#1}{#2}%
}
\makeatother

\mathdef{d}{\mathop{}\!\mathrm{d}}

\begin{document}

\d{x} is an x with a dot below and $\int f(x) \d x$ is an integral over $x$.

\end{document}

Why do I use \DeclareRobustCommand (first version) or \protected (second version) all around?

When TeX does a write operation it is in no mode at all, in particular it is not in math mode. A simplistic definition such as

\newcommand{\foo}{%
  \relax % if this comes first in an alignment
  \ifmmode
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
  \foo@math\foo@text
}

would always choose \foo@text if found in a \write. The above protections make the \mathdef commands to write themselves, so no choice is made at \write time.

Why not using \everymath? Try the following example and see.

\documentclass{article}

\everymath{\let\foo\foomath}
\newcommand{\foo}{Foo}
\newcommand{\foomath}{Ops}

\begin{document}

Text: \foo

Math: $\foo$

Ops: abc\textsuperscript{\foo}

\end{document}
  • Thanks egreg. Learned a lot from your answer. Still I would go with Sergei's answer, because it's a bit more concise. Just two small questions: Why wouldn't you go with everymath? Efficiency, because all the definitions have to be executed for every little formula ? Or is it more because of robustness? And, did you mean \ifmmode in the example? – Elmar Zander Mar 4 at 10:02
  • @ElmarZander Yes, efficiency is the main reason. But not the only one, see the addition. – egreg Mar 4 at 11:39
2

You wish to use the \PushPostHook-macro from the everyhook-package for (re)defining macros that process arguments?

Issue 1:

In LaTeX arguments are denoted by #1 and #2 and the like, i.e., by sequences of hashes trailed by a digit in the range 1..9.

When it comes to nesting definitions, hashes need to be doubled for the inner definitions:

\def\outsidemacro#1{%
  \def\insidemacro##1{This is insidemacro's argument: ##1.}%  
  This is outsidemacro's argument: #1.%
}

During expansion, two consecutive hashes will be collapsed into one hash, i.e., the amount of hashes will be halved.

I.e., \outsidemacro{foo} yields:

\def\insidemacro#1{This is insidemacro's argument: #1.}%  
This is outsidemacro's argument: foo.%

Looking at the definition of \PushPostHook via \show\PushPostHook yields:

> \PushPostHook=\protected\long macro:
#1#2->\eh@checkhook {#1}\PushPostHook \letcs \eh@tempi {eh@post#1}\expandafter 
\gdef \csname eh@post#1\expandafter \endcsname \expandafter {\eh@tempi \eh@hook
separator #2}\undef \eh@tempi .

As you can see, the tokens are kept in macros whose names are of pattern \eh@post⟨name of hook⟩.

E.g., \eh@postmath and \eh@postdisplay.

For adding tokens to such a macro, \PushPostHook lets the macro in question equal to \eh@tempi and then redefines the macro in question by appending the tokens in question behind the expansion of \eh@tempi.

Expanding \eh@tempi is a crucial point:

In case the definition of \eh@tempi contains hashes (#), during expansion two consecutive hashes will collapse into one of them.

This implies:

Whenever \PushPostHook is called for adding things to \eh@postmath or \eh@postdisplay, the amount of consecutive hashes with things that are already in \eh@postmath or \eh@postdisplay will be halved.

This will be a problem especially when calling \PushPostHook several times for adding things to \eh@postmath or \eh@postdisplay.

You can avoid the halving of the amount of consecutive hashes by maintaining things by means of a token register because when the content of a token register is "spit out" via \the, the amount of hashes will not be reduced. When "spitting out" due to \the takes place during \edef, the amount of hashes will not only be not reduced but it will be doubled.

If you do, e.g.,

\myscratchtoks{#}
\edef\mymacro{\the\myscratchtoks}

, in the definition of \mymacro the amount of hashes coming from \myscratchtoks will be doubled. When expanding \mymacro, that doubled amount will be halved and thus the expansion of \mymacro delivers the same amount of hashes as would be delivered by \the\myscratchtoks.

Therefore I suggest adding things to a token-register and using \PushPostHook only for "flushing" that token-register.

Issue 2:

If you wish to maintain macros that can also process arguments, I suggest implementing something that can be used similarly to the prefixes \long or \global.

In the example below I used #{-notation for implementing a macro \mathcommand which processes left-brace-delimited arguments that are trailed by brace-nested arguments. As the ⟨definition text⟩ of a macro always is to be nested in braces, you can use the processing of left-brace-delimited-arguments for fetching all tokens that come before a ⟨definition text⟩.
Such tokens can be the definition-command itself (e.g., \renewcommand* or \global\long\def), the control-sequence-token that is to be (re)defined, and the ⟨parameter text⟩.

E.g., with

\mathcommand\renewcommand*\mymacrowitharguments[2]{%
  \mbox{math-arg~1: }(#1) 
  \mbox{ math-arg~2: }(#2)
}%

, \mathcommand's first (left-brace-delimited) argument will be the sequence \renewcommand*\mymacrowitharguments[2] and its second argument is formed by the stuff that is nested inside braces: \mbox{math-arg~1: }(#1) \mbox{ math-arg~2: }(#2).
\mathcommand will add the sequence ⟨first argument⟩{⟨second argument⟩}, i.e., the sequence \renewcommand*\mymacrowitharguments[2]{\mbox{math-arg~1: }(#1) \mbox{ math-arg~2: }(#2) } to the token-register \mymathhooktoks.

I also implemented a macro \mathcommandfromname which also fetches a left-brace-delimited argument and takes the stuff that is behind that argument and that therefore is nested in braces for the name of a control-sequence-token which can be formed via \csname..\endcsname:

E.g.,

\mathcommandfromname\renewcommand*{mymacrowitharguments}[2]{%
  \mbox{math-arg~1: }(#1) 
  \mbox{ math-arg~2: }(#2)
}%

yields:

\mathcommand\renewcommand*\mymacrowitharguments[2]{%
  \mbox{math-arg~1: }(#1) 
  \mbox{ math-arg~2: }(#2)
}%

\documentclass{article}

\usepackage{everyhook}

\newtoks\myscratchtoks
\newcommand\mymathhookmacro{}%

\PushPostHook{math}{\mymathhookmacro}%
\PushPostHook{display}{\mymathhookmacro}%

\newcommand{\mathcommand}{}%
\long\def\mathcommand#1#{\innermathcommand{#1}}%
\newcommand{\innermathcommand}[2]{%
  \begingroup
  \expandafter\myscratchtoks\expandafter{\mymathhookmacro#1{#2}}%
  \xdef\mymathhookmacro{\the\myscratchtoks}%
  \endgroup
}

\newcommand\exchange[2]{#2#1}%
\newcommand\mathcommandfromname{}%
\long\def\mathcommandfromname#1#{\romannumeral0\innermathcommandfromname{#1}}%
\newcommand\innermathcommandfromname[2]{%
  \expandafter\exchange\expandafter{\csname#2\endcsname}{ \mathcommand#1}%
}%

%----------------------------------------------------------------

\newcommand*\mymacrowitharguments[2]{%
  non-math-arg~1: \textbf{(#1)} %
  non-math-arg~2: \textbf{(#2)}%
}%

\mathcommand\renewcommand*\mymacrowitharguments[2]{%
  \mbox{math-arg~1: }(#1)
  \mbox{ math-arg~2: }(#2)
}%

\newcommand*\myothermacrowitharguments[2]{%
  other-non-math-arg~1: \textbf{(#1)} %
  other-non-math-arg~2: \textbf{(#2)}%
}%

\mathcommandfromname\renewcommand*{myothermacrowitharguments}[2]{%
  \mbox{other-math-arg~1: }(#1)
  \mbox{ other-math-arg~2: }(#2)
}%

\mathcommand\renewcommand*\d{\mathrm{d}}%

\parindent=0ex

\begin{document}

\d x  is an x with a dot below and $\int f(x) \d x$ is an 
integral over $x$.

\bigskip

Testing with \verb|\mymacrowitharguments|:\smallskip

outside math:\\
\mymacrowitharguments{arg A}{arg B}
\smallskip

inside math:\\
$\mymacrowitharguments{arg A}{arg B}$
\bigskip

Testing with \verb|\myothermacrowitharguments|:\smallskip

outside math:\\
\myothermacrowitharguments{arg A}{arg B}
\smallskip

inside math:\\
$\myothermacrowitharguments{arg A}{arg B}$

\end{document}

enter image description here

  • Thanks for all the information. Actually, I didn't /wish/ to use PushPostHook, it was just the only thing I could come up with. I still do not quite understand the #1# notation. What exactly does it mean? – Elmar Zander Mar 4 at 9:56
  • @ElmarZander It should be #{-notation - sorry. It was discussed yesterday in What is “# Notation”? How does the # syntax work? – Ulrich Diez Mar 4 at 9:59

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.