4

I'm working on building an expenses package. The intention is to be able to write

\expense{someone}{something}{something a bit longer}{10}{GBP}
\expense{someone else }{something else}{something a bit longer}{11}{EUR}
\makeexpensetable

To do this, I am starting an internal \allexpenses macro

\def\allexpenses{}

Then each \expense command appends to that a \writeexpense command defined as

\newcommand{\writeexpense}[5]{%
    #1 & #2 & #4 \\ %
}

So that eventually the \makeexpensetable command will simply begin a table, then have an \allexpenses line containing all the rows and end the table.

My current \expense command is

\newcommand{\expense}[5]{%
    \edef\allexpenses{\allexpenses%
        \writeexpense{#1}{#2}{#3}{#4}{#5}%
    }%
}

However, TeX is throwing errors due to the presence of the \writeexpense command inside. How do I stop that command from expanding? I'm guessing the answer has something to do with the correct use of a \noexpand command, but I cannot figure it out.

6

Alternative, @-free solution:

\usepackage{etoolbox}
\appto\allexpenses{\writeexpense{#1}{#2}{#3}{#4}{#5}}

There are also one or two package-free solutions, but they effectively reinvent the \appto wheel. The problem is that \edef expands its contents recursively, and you only want the initial \allexpenses to be expanded once. In fact, it's not \noexpand but \unexpanded that you want:

\edef\allexpenses{%
  \expandafter\unexpanded\expandafter{\allexpenses}%
  \unexpanded{\writeexpense{#1}{#2}{#3}{#4}{#5}}%
}

This causes \allexpenses to be expanded once into whatever it contains, and then those contents to be protected from further expansion. The first line is equivalent to \expandonce\allexpenses, where \expandonce is also defined in etoolbox. The eTeX-free solution is to use a token register for this:

\toks0=\expandafter{\allexpenses \writeexpense{#1}{#2}{#3}{#4}{#5}}
\edef\allexpenses{\the\toks0}

Token registers were the original \expandonce, but since their assignment is not fully expandable, they are not always suitable where this eTeX-based macro is.

  • The first \expandafter in the second solution is redundant. The third solution is wrong because \writeexpense would be expanded! Just put it in \toks0 beforehand. – egreg Apr 10 '13 at 14:10
  • Both the second and third solution would edef-expand \writeexpense and all its arguments, meaning no fragile commands (such as accented letters) could be used in the arguments – David Carlisle Apr 10 '13 at 14:42
  • Fixed, @both of you. – Ryan Reich Apr 10 '13 at 14:44
  • 1
    Also some of us like solutions with as many @ as possible. – David Carlisle Apr 10 '13 at 14:47
  • I put one in my comment just for you :) – Ryan Reich Apr 10 '13 at 14:48
5

use \g@addto@macro\allexpenses{\writeexpense{#1}{#2}{#3}{#4}{#5}}
in a package file or between \makeatletter \makeatother

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.