3

Let's say we have a command \foo with 1 argument. Can we produce a command \setfoo{aaa}{<some thing>} which redefines \foo to: if an argument of \foois equal to 'aaa', do ; otherwise do what \foo was supposed to do previously? I would also like to use \setfoo many times, so

\setfoo{a}{part1}
\setfoo{b}{part2}
\setfoo{c}{part3}
\foo{a}  \foo{b} \foo{c}

would produce

part1 part2 part3

I've tried the following:

\documentclass{article}
\usepackage{ifthen}

\newcommand{\foo}[1]{}
%\let\oldfoo\foo%
\newcommand{\setfoo}[2]{
\let\oldfoo\foo %<- to save current \foo
\renewcommand{\foo}[1]{
\ifthenelse{\equal{##1}{#1}}{#2}{\oldfoo{##1}}%
}
}
\begin{document}
\setfoo{a}{part1}
\setfoo{b}{part2}
%\setfoo{c}{part3}

\foo{a} \foo{a} \foo{c}

\end{document}

But it works only if there are <=2 uses of \setfoo. Otherwise, compilation doesn't stop for a few minutes so I guess something is not working. How can this be fixed? Thanks in advance.

1
  • 1
    Welcome to TeX.SE!
    – Mensch
    Commented Jan 22, 2019 at 23:58

2 Answers 2

3

This is a job for \csname:

\newcommand{\setfoo}[2]{%
  \expandafter\newcommand\csname tomasz@#1\endcsname{#2}%
}
\newcommand{\foo}[1]{\csname tomasz@#1\endcsname}

You might use a check in \foo that the command is actually defined:

\makeatletter
\newcommand{\foo}[1]{%
  \ifcsname tomasz@#1\endcsname
     \expandafter\@firstoftwo
  \else
     \expandafter\@secondoftwo
  \fi
  {\csname tomasz@#1\endcsname}%
  {BUMMER!}%
}
\makeatother
2
  • I was using this wonderful solution for a while, but today I had a problem: if I use \setfoo inside enumerate environment, I can't recover information in \foo outside this environment. Is there a easy way to fix it? Shall I post another question?
    – Tomasz23
    Commented Jul 20, 2019 at 1:41
  • @Tomasz23 Possibly, but with some more details about your aim.
    – egreg
    Commented Jul 20, 2019 at 9:14
1

In your special case, where \foo is always to process a single undelimited non-optional argument, you can probably apply some expansion trickery for "flushing" the tokens that form the current definition of \foo into the new definition of \foo—one of the expansion-tricks is (ab)using \romannumeral for triggering expansion until LaTeX has found the number 0. \romannumeral's underlying conversion-routine does "swallow" non-positive numbers while silently not delivering any token at all:

\documentclass{article}
\usepackage{ifthen}

\newcommand\PassFirstToSecond[2]{#2{#1}}%

\newcommand{\foo}[1]{There is no setting for value #1.}

\newcommand{\setfoo}[2]{%
  \expandafter\PassFirstToSecond
  \expandafter{%
    \romannumeral\expandafter\PassFirstToSecond\expandafter{\foo{##1}}%
    {0 \ifthenelse{\equal{##1}{#1}}{#2}}%
  }{\renewcommand{\foo}[1]}%
}

\parindent=0ex
\parskip=\bigskipamount

\begin{document}

\texttt{\string\foo\space currently is defined as:\\ \meaning\foo}

\setfoo{a}{part1}
\texttt{\string\foo\space currently is defined as:\\ \meaning\foo}

\setfoo{b}{part2}
\texttt{\string\foo\space currently is defined as:\\ \meaning\foo}

\setfoo{c}{part3}
\texttt{\string\foo\space currently is defined as:\\ \meaning\foo}

\hrulefill

Some testing:

\verb|\foo{a}| yields: \foo{a} 

\verb|\foo{b}| yields: \foo{b} 

\verb|\foo{c}| yields: \foo{c}

\verb|\foo{y}| yields: \foo{y}

\end{document}

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .