# Nested macro definition seems to not expand argument

I'm trying to define a simple way to handle keywords in my university thesis template. They are used in different parts of the thesis, with different notations, so I decided to keep them in different macros. I did a similar in the past thing to keep the examiners' names.

It works fine when defining them one by one, like:

\myKeyword{key 1}
\myKeyword{key 2}


I tried then to create a macro where I could declare all of them together, but keep them still separated (for further use). However, for some reason, it does not work as I expected.

Here is an MWE:

\documentclass{standalone}

\usepackage{tikz} %foreach
\usepackage{forloop} %forloop

% counters declaration
\newcounter{myKeywordCounter}
\newcounter{currentKeywordCounter}

\newcommand{\myKeyword}[1]{%
\expandafter\newcommand\csname myKeyword\arabic{myKeywordCounter}\endcsname{#1}\relax%
\stepcounter{myKeywordCounter}%
}%

\newcommand{\declareKeywords}[1]{%
\foreach \argtext in {#1} {%
\myKeyword{\argtext}%
}%
}%

\newcommand{\printKeywords}{\textbf{Keywords}: %
\forloop{currentKeywordCounter}{0}{\value{currentKeywordCounter} < \value{myKeywordCounter}}%
{%
\expandafter\csname myKeyword\arabic{currentKeywordCounter}\endcsname{}. %
}%
}%

\begin{document}
\declareKeywords{{key A},{key B},{key C}}
\myKeyword{key 1}
\myKeyword{key 2}
\myKeyword{key 3}
\printKeywords{}
\end{document}


Which prints only keys A, B, and C, whereas does not print 1, 2, and 3:

It seems that when nested, the new 'myKeywordX' (X is an arabic number) is not able to expand to #1. I'm not sure about that... Any thoughts?

• Untested, but I think this is the grouping caused by \foreach... – user31729 Dec 12 '17 at 17:43
• You should look into the expl3 language enhancements, it might be easier to achieve with those what you request – user31729 Dec 12 '17 at 17:54

The grouping caused by \foreach will never give \mykeyword0 etc. being defined, so it will not change.

The easiest way is to use either a \global\@namedef or a \gdef macro together with the expanded value of \argtext

\documentclass{article}

\usepackage{tikz} %foreach
\usepackage{forloop} %forloop

% counters declaration
\newcounter{myKeywordCounter}
\newcounter{currentKeywordCounter}

\newcommand{\myKeyword}[1]{%
\expandafter\gdef\csname myKeyword\arabic{myKeywordCounter}\endcsname{#1}\relax%
\stepcounter{myKeywordCounter}%
}%

\newcommand{\declareKeywords}[1]{%
\foreach \argtext in {#1} {%
\expandafter\myKeyword\expandafter{\argtext}%
}%
}%

\newcommand{\printKeywords}{\textbf{Keywords}: %
\forloop{currentKeywordCounter}{0}{\value{currentKeywordCounter} < \value{myKeywordCounter}}%
{%
\expandafter\csname myKeyword\arabic{currentKeywordCounter}\endcsname{}. %
}%
}%

\begin{document}
\declareKeywords{{key A},{key B},{key C}}
%  \myKeyword{key 1}
%  \myKeyword{key 2}
%  \myKeyword{key 3}
\printKeywords{}
\end{document}

• Tks, it works! I understand the gdef, but i didnt understand well the \expandafters in the foreach part. Could you elaborate on that? Is this because gdef canot use an 'unexpanded' macro? – Isma Dec 12 '17 at 17:55
• @Isma: On the usage of \printKeywords \csname mykeyword0\endcsname would try to expand \argtext which isn't defined any longer in \printKeywords -- you have to force the replacement text (i.e. the expansion of the relevant \argtext from the loop into the \mykeyword{\argtext}, i.e. \expandafter\mykeyword\expandafter{\argtext} One \expandafter is not enough there, i.e. \expandafter\mykeyword{\argtext} would try to expand the {, which is not expandable, you have to 'jump' over the \mykeyword, expand the argument \argtext and then let \mykeyword do the job – user31729 Dec 12 '17 at 18:00
• I see it now! Tks again ! – Isma Dec 12 '17 at 18:02
• @Isma: You're welcome. Happy TeXing – user31729 Dec 12 '17 at 18:03

The grouping in \foreach is the cause of your troubles.

Here's a different implementation based on expl3, where each \myKeyword or \declareKeywords command add the item to a sequence that can be later processed.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\myKeyword}{m}
{
}

\NewDocumentCommand{\declareKeywords}{m}
{
\clist_map_inline:nn { #1 }
{
}
}

\NewDocumentCommand{\printKeywords}{}
{
Keywords:~
\seq_map_inline:Nn \g_isma_keywords_seq
{
##1.~
}
}

\NewDocumentCommand{\getKeyword}{m}
{
\seq_item:Nn \g_isma_keywords_seq { #1 }
}

\seq_new:N \g_isma_keywords_seq

{
\seq_gput_right:Nn \g_isma_keywords_seq { #1 }
}

\ExplSyntaxOff

\begin{document}

\declareKeywords{key A,key B,key C}

\myKeyword{key 1}
\myKeyword{key 2}
\myKeyword{key 3}

\printKeywords

\getKeyword{2}

\getKeyword{4}

\end{document}
`