5

I want to create a simple map using \newcommand. My \NewMapItem command defines another command which returns item's value. \MapItem simply replaces to that command.

\documentclass{article}
\newcommand{\NewMapItem}[2]{\newcommand{\Map@#1}{#2}}
\newcommand{\MapItem}[1]{\Map@#1}
\begin{document}
    \NewMapItem{Canberk}{Qwerty}
    \MapItem{Canberk}
\end{document}

But it doesn't works. Output is:

line 5: Missing number, treated as zero. \NewMapItem{Canberk}{Qwerty}
line 5: You already have nine parameters. \NewMapItem{Canberk}{Qwerty}

Could you explain?

5

See Latex dynamic macro definition for the \NewMapItem problem and also How to know whether or not we need \expandafter? for a discussion about the matter.

\newcommand{\NewMapItem}[2]{%
  \expandafter\newcommand\csname Map@#1\endcsname{#2}}
\newcommand{\MapItem}[1]{\csname Map@#1\endcsname}

You can't form a token in that way unless you use \csname.


A different solution with expl3:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
% allocate a global property list
\prop_new:N \g_jnbrq_maps_prop

% the user level command for adding properties
\NewDocumentCommand{\NewMapItem}{mm}
 {
  \prop_gput:Nnn \g_jnbrq_maps_prop { #1 } { #2 }
 }
% the user level command for retrieving a property
\DeclareExpandableDocumentCommand{\MapItem}{m}
 {
  \prop_item:Nn \g_jnbrq_maps_prop { #1 }
 }
\ExplSyntaxOff

\begin{document}

\NewMapItem{Canberk}{Qwerty}

\MapItem{Canberk}

\end{document}

It's possible to check whether the property already exists:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
% allocate a global property list
\prop_new:N \g_jnbrq_maps_prop
% an error message for duplicate property
\msg_new:nnnn { jnbrq/maps } { duplicate-property }
 {
  Already~existing~property~#1
 }
 {
  Property~#1~is~already~defined,~I'm~ignoring~
  this~redefinition
 }

% the user level command for adding properties
\NewDocumentCommand{\NewMapItem}{mm}
 {
  \prop_if_in:NnTF \g_jnbrq_maps_prop { #1 }
   {
    \msg_error:nnn { jnbrq/maps } { duplicate-property } { #1 }
   }
   {
    \prop_gput:Nnn \g_jnbrq_maps_prop { #1 } { #2 }
   }
 }
% the user level command for retrieving a property
\DeclareExpandableDocumentCommand{\MapItem}{m}
 {
  \prop_item:Nn \g_jnbrq_maps_prop { #1 }
 }
\ExplSyntaxOff

\begin{document}
\NewMapItem{Canberk}{Qwerty}
\NewMapItem{Canberk}{QQQ}

\MapItem{Canberk}
\end{document}

This will raise an error

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! jnbrq/maps error: "duplicate-property"
! 
! Already existing property Canberk
! 
! See the jnbrq/maps documentation for further information.
! 
! For immediate help type H <return>.
!...............................................  

l.37 \NewMapItem{Canberk}{QQQ}

? h
|'''''''''''''''''''''''''''''''''''''''''''''''
| Property Canberk is already defined, I'm ignoring this redefinition
|...............................................

which would be more easily understood instead of the standard error issued by \newcommand.

|improve this answer|||||
  • Why \newcommand when we have \def? The vicinity of \newcommand and \csname/\endcsname seems to me very non-standard:). – wipet Apr 17 '15 at 19:43
  • @wipet Because \newcommand checks for duplicate definitions, while \def doesn't. – egreg Apr 17 '15 at 19:47
  • But the \csname Map@soemthing\endcsname cannot be duplicate. If this is not true then you have chosen bad prefix Map@. And when user type \NewMapItem{the same as before} then it is clear that user needs to re-define it. – wipet Apr 17 '15 at 19:51
  • @wipet I don't think so, judging from the original code. – egreg Apr 17 '15 at 19:57

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.