13

Well, it's been in my head for some time, but I haven't got anything out of it, so I ask here. At what places could be useful to have \edef\foo#1{..}? What applications could it have? Is it useful at all?

Here's one example. \foo gives ten thousand times the argument after one expansion. Of course, this probably could be done in another way, but seems like a good example.

\def\byten#1{#1#1#1#1#1#1#1#1#1#1}
\edef\foo#1{\byten{\byten{\byten{\byten{#1}}}}}

Ten thousand letters: \foo{a\hskip0ptplus1pt}
\bye

But apart from that, I've been looking for a chance to use \edef\foo#1 and it hasn't appeared.

To make this answerable, in case some applications don't appear, or there's no interest in the question, it could also be answered like Have you ever seen \edef used that way? or for instance Is there any use of this in a full TeX Live installation?

Note

The question is not clear enough, the suggestions of egreg and Heiko are both acceptable answers, since they are uses of \edef with arguments. However, what I was looking for are situations where the argument are inside the argument of a macro that gets expanded when \edefed (like in my example). I don't know how to write this clear, feel free to edit the question.

  • 1
    There are some examples in etoolbox.sty – egreg Aug 18 '15 at 19:40
  • Those are indeed examples, \edefs with arguments. But not what I was looking for; I mean, those examples are just “basic” just stop expansion for a few things and expand just one bit (e.g., a \detokenize). I was looking more about uses where #1 is expanded inside a macro inside the \edef. – Manuel Aug 18 '15 at 19:46
  • That always happens with \write. Note that in your example you don't expand #1: only macros get expanded in \edef. Doing \edef\foo#1{\byten{#1}} is the same as doing \def\foo{#1#1#1#1#1#1#1#1#1#1} – egreg Aug 18 '15 at 19:48
  • That's what I (tried to) mean, I know #1 is not expanded, but is “moved around” by the expanded macros. If you, or anyone, can clear the question, feel free to edit. I don't understand what you mean about \write, though. – Manuel Aug 18 '15 at 19:51
15

Searching for \edef or \xdef (global variant) with command to be defined and argument in TeX Live 2015 and filtering out possible false positives (when the command is constructed with \csname):

 egrep -r '\\[ex]def\\[a-zA-Z@]+#1' texmf-dist/tex/ | grep -v '\\[ex]def\\csname'

Result are 219 lines.

I do not want to discuss all findings, thus I restrict myself to few examples.

Example \TextOrMath of the LaTeX kernel (latex.ltx)

Recently, macro \TextOrMath was added to the LaTeX kernel:

\edef\TextOrMath#1#2{%
  \expandafter\noexpand\csname TextOrMath\space\endcsname
  {#1}{#2}}

Here, the \edef has the purpose to construct a macro name with a space in it: \TextOrMath␣. The definition would simpler, if the space would be a letter:

\def\TextOrMath#1#2{\TextOrMath␣{#1}{#2}}

But, this is not possible with the usual category code of the space. An alternative with \def and lots of \expandafter is more cumbersome:

\expandafter\def\expandafter\TextOrMath
\expandafter#\expandafter1\expandafter#\expandafter2\expandafter{%
  \csname TextOrMath\space\endcsname{#1}{#2}%
}

Therefore, \edef works on the non-argument part of the definition text. To make it clear, arguments are not expanded during the definition with \edef, #1 to #9 are non-expandable tokens.

Example \split@err of package amsmath

Another example can be found in package amsmath:

\edef\split@err#1{%
    \@nx\@amsmath@err{%
        \string\begin{split} won't work here%
    }{%
        \@xp\@nx\csname
  Did you forget a preceding \string\begin{equation}?^^J%
  If not, perhaps the `aligned' environment is what
  you want.\endcsname}%
}

Here, the argument is not used at all, it is ignored as part of the error recovery.

Example \mleftright@Def of package mleftright

Package mleftright has an example, where the argument is used three times:

\edef\mleftright@Def#1{%
  \noexpand\ltx@IfUndefined{%
    \noexpand\expandafter\noexpand\ltx@gobble\noexpand\string#1%
  }{%
    \expandafter\noexpand\mleftright@Def#1%
  }{%
    \noexpand\@PackageError{mleftright}{%
      Command \noexpand\string#1 already defined%
    }\noexpand\@ehd
    \noexpand\ltx@gobble
  }%
}

The purpose of the expansion is \mleftright@Def inside the definition. Previously, it was defined as \protected\def, \DeclareRobustCommand* or \def, depending, which method is available (e-TeX, LaTeX, or neither of them).

Arguments #1, ...

At definition time, the argument place holders (#1, #2, ..., #9) are just two non-expandable tokens, the hash character # and the digit 1 to 9. Therefore, there isn't a difference between \edef or \def, because \edef cannot expand non-expandable tokens.

The argument place holders get replaced with the actual arguments, when the macro is used, that is after the definition of the macro.

  • This falls into the same category as egreg noted (like etoolbox.sty), where the #1 isn't “moved” by the \edef, just other things are expanded. Of course #n aren't expanded, there's nothing for them to expand :) I will wait a little bit to see if there's a case where the arguments are moved when macros are expanded, and, if it doesn't appear, I guess I will accept this. – Manuel Aug 18 '15 at 21:14
  • @Manuel I do not know, what you mean with "moved", but I have added two further examples, which do different things with arguments: The argument in the first added example is not used at all and in the other example the argument is used three times. – Heiko Oberdiek Aug 19 '15 at 2:30
  • I don't know how to state it clearly, I mean that the #1 is inside the argument of a macro that gets expanded when \edefed. – Manuel Aug 19 '15 at 11:05
  • @Manual As I said in the answer, #1 consists of two non-expandable tokens # and 1. \edef does not see anything different. The #1 gets replaced, when the macro is used. – Heiko Oberdiek Aug 19 '15 at 11:07
  • 2
    @Manuel \@gobbletwo could be defined using \@gobble: \long\edef\@gobbletwo#1#2{\@gobble{#1}\@gobble{#2}} – Heiko Oberdiek Aug 19 '15 at 12:11
4

After a completely false understanding of the question, I have rewritten my answer to show how \edef with an argument can be used to "fix" the selected equation citation style.

An \edef is evaluated at time of definition, whereas \def is evaluated at time of execution. If \edef\eqcite#1{} is used in preference to \def\eqcite#1{}, then changes to the supporting formatting macro have no effect, because the \edef locks in the definition. In contrast, when using \def, changes to the supporting formatting macro will affect the subsequent equation citations.

Thus, philosophically, the use of \edef should be employed when one wants something not to change even if the supporting macros are changed. The below MWE tries to capture the choice at hand: the use of \def allows \setrefstyle to change the \eqcite behavior on the fly, whereas the \edef prevents \setrefstyle from having any subsequent effect.

\documentclass{article}
\let\svref\ref
\def\setrefstyle#1{\ifcase#1\relax
  \def\refstyle##1{Eq.\,(##1)} \or
  \def\refstyle##1{Eqn.\,(##1)} \or
  \def\refstyle##1{equation~##1} \else\fi
}
\setrefstyle{0}% 

% HERE IS THE CHOICE:
\newcommand\fixeqcite[1][T]{%
  \if T#1%
    \edef\eqcite##1{\refstyle{\noexpand\ref{##1}}}% <--- TO NOT ALLOW CHANGES
  \else%
    \def\eqcite##1{\refstyle{\ref{##1}}}%<--- TO ALLOW CHANGES
  \fi%
}
\fixeqcite
\begin{document}
\begin{equation}
\label{eq:A}
y=mx+b
\end{equation}
\def\mytest{\smallskip\par
\setrefstyle{0}In \eqcite{eq:A} we see one form of cite\par
\setrefstyle{1}In \eqcite{eq:A} do we see another form of cite?\par
\setrefstyle{2}In \eqcite{eq:A} do we see a third form of cite?\bigskip\par}

Eqcite definition (with edef) is of fixed format, by default.\mytest
But I can let it be redefined (with def) on the fly.\fixeqcite[F]\mytest
\end{document}

enter image description here

  • But here you are using \edef\foo{..}, so \foo has no arguments. This is the normal use of \edef. – Manuel Aug 19 '15 at 12:14
  • @Manuel Apparently, I misunderstood the question. I'll delete and rethink. – Steven B. Segletes Aug 19 '15 at 12:15
  • @Manuel I have totally revised my answer. – Steven B. Segletes Aug 19 '15 at 13:31
  • Well, this is one of those things I was looking for. Not magical, but gets to the point. I'm looking for cases where the benefit could be clear. And if no case of those appear, then I'm looking for packages that already use this “trick” on TeX Live, for instance. – Manuel Aug 19 '15 at 14:16
  • 1
    @Manuel I have revised my answer to better lay out the \edef/\def distinction and how it may be used to achieve a desired behavior. – Steven B. Segletes Aug 19 '15 at 14:25
3

There is a usage of \edef with parameter in special expansion control. One nice (yet quite complicated) example can be found in skeyval-core.tex v1.3 on line 1997

\skvrobustdef*\skvpopfunctions#1#2{%
  \begingroup
  \edef\skv@elt{\skvnoexpandcs{\skvremovescape{#1}@skv@stack}}%
  \expandafter\skvifdefTF\skv@elt{%
    \expandafter\ifx\skv@elt\@empty
      \skv@err{Stack of '\noexpand#1' is empty}\skv@ehd
    \fi
  }{%
    \skv@err{Stack of '\noexpand#1' is undefined}\skv@ehd
  }%
  \edef\skv@prova{\skvexpandtwice\skv@elt}%
  \edef\skv@provb##1##{\endgroup##1\gdef\skvexpandonce\skv@elt}%
  \expandafter\skv@provb\skv@prova
  \skvgadvanceno#2\m@ne
}

I'm not sure I understand the details, but certainly \skv@provb is defined by \edef, standard \def wouldn't work here (since \skcexpandonce is used inside) and it takes an argument.

This is a significantly more complicated case of what Heiko shows; here you could probably get around having \edef\....##1 in the code if you wished, but the effort to do so would have to be really big.

  • This is not an example of what I'm looking for. Here ##1 is not “touched” inside of the \edef. – Manuel Aug 19 '15 at 14:11
0

Well, here's one of the uses I was looking for (it's practically the same code I used in the question, but at least it's public and useful code :D)

The l3benchmark package, at lines 420–421 has a nice definition of \@@_replicate_kibi_fold:n (@@ is symbolic):

\cs_new:Npx \@@_replicate_kibi_fold:n #1
  { \prg_replicate:nn {1024} {#1} }

As its name indicates, expanding this function once yields 1024 copies of its argument. This is used to avoid reaching the limits of TeX's memory in case the user input is a very simple piece of code.

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.