3

I'm just getting started with LaTeX, and I'm already struggling with the very basic stuff.

I create 2 commands, each assigning a value to a variable:

\newcommand{\firstname}[1]{\def\@firstname{#1}}
\newcommand{\lastname}[1]{\def\@lastname{#1}}

These variables are set using the commands somewhere at the beginning of the document:

\firstname{Kevin}
\lastname{De Coninck}

When I try to print the lastname, everything works fine, when I try to print the firstname, the following error is returned Use of \@ doesn't match its definition. \@f

I'm priting inside my document using the following code:

\begin{document}
    \@firstname
\end{document}

What am I missing here?

Update: Entire document

% ----------------------------------------------------------------------
% -- CONFIGURATION
% ----------------------------------------------------------------------
\documentclass[11pt, a4paper]{article}

% ----------------------------------------------------------------------
% -- PACKAGES
% ----------------------------------------------------------------------
\RequirePackage{geometry}

% ----------------------------------------------------------------------
% -- COMMAND DEFINITIONS
% ----------------------------------------------------------------------

% Summary: Configure the person's name.
% Usage:   \name{<firstname>}{<lastname>}
%          firstname{<firstname>}
%          lastname{<lastname>}
\newcommand{\firstname}[1]{\def\@firstname{#1}}
\newcommand{\lastname}[1]{\def\@lastname{#1}}

% ----------------------------------------------------------------------
% -- LAYOUT CONFIGURATION
% ----------------------------------------------------------------------
\geometry{left=2.0cm, top=5.5cm, right=2.0cm, bottom=2.0cm, footskip=.5cm}

% ----------------------------------------------------------------------
% -- PERSONAL DATA
% ----------------------------------------------------------------------
\firstname{Kevin}
\lastname{De Coninck}

% ----------------------------------------------------------------------
% -- ACTUAL DOCUMENT
% ----------------------------------------------------------------------
\begin{document}
    \@firstname
    \@lastname
\end{document}
  • \makeatletter\@firstname\makeatother, but you should define a wrapper command as well – user31729 Feb 1 '17 at 14:29
  • 1
    @ is a special character, in the sense that, in packages, it is considered a "letter", whereas in a document, it is considered an "other", and precluded from use in variable names. As Christian indicates, you can make @ function as a letter in documents with the invocation of \makeatletter. This then allows its use in variable names such as \@firstname, etc. – Steven B. Segletes Feb 1 '17 at 14:30
  • \newcommand{\printnames}{\@lastname, \@firstname} in a stylefile or between \makeatletter ... \makeatother as Christian pointed out and command \printnames in your document. – Jan Feb 1 '17 at 14:32
  • I don't get it. Using the code Christian supplies renders irstname. – Complexity Feb 1 '17 at 14:32
  • 1
    Instead of writing @ in the holder macro, why not just write CMPLX, then the macros should the prefixed enough and \CMPLXfirstname works out of the box. Macros with @ in their name is genrally for intenal use and for experienced users. – daleif Feb 1 '17 at 14:38
3

I've added the usual \makeatletter...\makeatother pair around the definitions and usage.

Please keep daleif's proposition in mind too: \CMPLXfirstname seems to be better and easier.

I've also changed \RequirePackage into \usepackage (although the first one is allowed too, but rather meant for packages only, not for normal documents)

Now, @ is special character that is reserved as part of names of internal commands which should not be accessible easily for a normal document user. Outside of packages or class files @ is not considered to be an allowed letter for command names, so \makeatletter changes this (temporarily), permitting @ to be part of such names and \makeatother reverts this.

% ----------------------------------------------------------------------
% -- CONFIGURATION
% ----------------------------------------------------------------------
\documentclass[11pt, a4paper]{article}

% ----------------------------------------------------------------------
% -- PACKAGES
% ----------------------------------------------------------------------
\usepackage{geometry}

% ----------------------------------------------------------------------
% -- COMMAND DEFINITIONS
% ----------------------------------------------------------------------

% Summary: Configure the person's name.
% Usage:   \name{<firstname>}{<lastname>}
%          firstname{<firstname>}
%          lastname{<lastname>}
\makeatletter
\newcommand{\firstname}[1]{\def\@firstname{#1}}
\newcommand{\lastname}[1]{\def\@lastname{#1}}

 \newcommand{\printname}{%
  \@ifundefined{@firstname}{}{\@firstname} \@ifundefined{@lastname}{}{\@lastname}%
}

\makeatother

% ----------------------------------------------------------------------
% -- LAYOUT CONFIGURATION
% ----------------------------------------------------------------------
\geometry{left=2.0cm, top=5.5cm, right=2.0cm, bottom=2.0cm, footskip=.5cm}

% ----------------------------------------------------------------------
% -- PERSONAL DATA
% ----------------------------------------------------------------------
\firstname{Kevin}
\lastname{De Coninck}

% ----------------------------------------------------------------------
% -- ACTUAL DOCUMENT
% ----------------------------------------------------------------------
\begin{document}
\makeatletter
    \@firstname\ \@lastname
\makeatother

Or \printname%
\end{document}

enter image description here

  • Do \firstname and \lastname really need to process arguments if all they do with the arguments is fetching them and putting them at the end of their replacement text? – Ulrich Diez Feb 1 '17 at 23:37
0

In case you don't wish to use \makeatletter..\makeatother, you can use
\csname..\endcsname:

\csname @firstname\endcsname → \@firstname.
\csname @lastname\endcsname → \@lastname.

I have written a small wrapper for \csname..\endcsname:

The macro \CreateCsFromName works as follows:

\CreateCsFromName<preceding tokens with no curly braces>{ControlSequence}
→ <preceding tokens with no curly braces>\ControlSequence.

If you omit <preceding tokens with no curly braces>, i.e., if you leave <preceding tokens with no curly braces> empty, then \CreateCsFromName will just construct the control sequence token from the name of the control sequence:

\CreateCsFromName{macro} → \macro

Instead of leaving <preceding tokens with no curly braces> empty, you can supply whatsoever commands for (re)defining:

\CreateCsFromName\long\def{macro} → \long\def\macro

\CreateCsFromName\long\def{macro}#1#2{First argument: #1, second argument: #2}
→ \long\def\macro#1#2{First argument: #1, second argument: #2}

\CreateCsFromName\newcommand*{macro} → \newcommand*\macro

\CreateCsFromName\newcommand*{macro}[2]{First argument: #1, second argument: #2}
→ \newcommand*\macro[2]{First argument: #1, second argument: #2}

Example:

\documentclass{article}

\newcommand\Exchange[2]{#2#1}
\newcommand\CreateCsFromName{}
\long\def\CreateCsFromName#1#{\romannumeral0\InnerCreateCsFromName{#1}}
\newcommand\InnerCreateCsFromName[2]{%
  \expandafter\Exchange\expandafter{\csname#2\endcsname}{ #1}%
}

% raise an error in case \@firstname and \@lastname are already defined:
\CreateCsFromName\newcommand*{@firstname}{}
\CreateCsFromName\newcommand*{@lastname}{}

% commands for silently redefining \@firstname and \@lastname:
\newcommand{\firstname}{\CreateCsFromName\def{@firstname}}
\newcommand{\lastname}{\CreateCsFromName\def{@lastname}}

\firstname{Kevin}
\lastname{De Coninck}

\begin{document}

\CreateCsFromName{@firstname} \CreateCsFromName{@lastname}

\end{document}

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.