0

How can I have a variable in variable name while writing to aux file in the answer on this link: https://tex.stackexchange.com/a/416272/192717

For example, from the above link:

\edef\mysuffix{helloworld}
% define variable with variable suffix \mysuffix
\definevalue{tester\mysuffix}{42}

% and use it elsewhere
\usevalue{tester\mysuffix}

Currently, I get this understandable error:

! Undefined control sequence.
<argument> usevalue@tester\mysuffix

l.37 ... \global \@namedef {tester\mysuffix }...

AFAIK, the problem will be resolved if I we are able to expand and write the variable name in the aux file, something like this:

\global \@namedef {testerhelloworld }...
2
  • 3
    please edit the question to make a single complete example that reproduces the error. macros expand by default as being written to a file so it is hard to understand your question, and you do not show the error that you got. Dec 12 '19 at 12:49
  • 1
    By "complete", David means starting with \documentclass and ending with \end{document}. Dec 12 '19 at 13:47
1

Don't use \unexpanded.

\documentclass{article}

\makeatletter
\newcommand{\usevalue}[1]{%
  \ifcsname usevalue@#1\endcsname
    \csname usevalue@#1\endcsname
  \else
    ??%
  \fi
}
\newcommand{\definevalue}[2]{%
  \begingroup\edef\x{\endgroup
    \write\@auxout{%
      \global\string\@namedef{usevalue@#1}{#2}%
    }%
  }\x
}
\makeatother

\def\mysuffix{helloworld}

\begin{document}

\usevalue{tester\mysuffix}

\definevalue{tester\mysuffix}{42}

\end{document}

This prints “42”.

The contents of the .aux file is

\relax 
\global \@namedef{usevalue@testerhelloworld}{42}

However, the original code works, provided you define \mysuffix before \begin{document} as it should.

\documentclass{article}

\makeatletter
\newcommand{\usevalue}[1]{%
  \ifcsname usevalue@#1\endcsname
    \csname usevalue@#1\endcsname
  \else
    ??%
  \fi
}
\newcommand{\definevalue}[2]{%
  \write\@auxout{%
    \unexpanded{\global\@namedef{usevalue@#1}{#2}}%
  }
}
\makeatother

\newcommand{\mysuffix}{helloworld}

\begin{document}

Something with \usevalue{tester\mysuffix}.

Something else.

Now we can define \texttt{tester} and use again it: \usevalue{tester\mysuffix}.

\definevalue{tester\mysuffix}{42}

\end{document}
0

You can implement infrastructure for defining and retrieving values analogous to the existing \label-\ref-mechanism of the LaTeX 2ε-kernel.

The example below provides the following user-macros:

  • \valueundefinederror{⟨name of value⟩}

    Triggers an error-message if value is undefined, else do nothing.
    Corresponds to \refused of Heiko Oberdiek's refcount-package.

  • \usevalue[{⟨tokens in case value is undefined⟩}]{⟨name of value⟩}

    If no optional argument is provided, \valueundefinederror{⟨name of value⟩}\nfss@text{\reset@font\bfseries??} is delivered in case value is undefined.
    Corresponds to \ref of the LaTeX 2ε-kernel if no optional argument is provided.

  • \usevalueexpandable{⟨name of value⟩}{⟨tokens in case value is undefined⟩}

    Corresponds to \getrefnumber of Heiko Oberdiek's refcount package.

  • \immediatedefinevalue{⟨name of value⟩}{⟨tokens to deliver when using the value⟩}

    Almost corresponds to \def\@currentlabel{...}...\label{...} of the LaTeX 2ε-kernel.
    Unlike with \label, the \write to .aux-file is done immediately.)

  • \definevalue{⟨name of value⟩}{⟨tokens to deliver when using the value⟩}

    Corresponds to \def\@currentlabel{...}...\label{...} of the LaTeX 2ε-kernel.
    Like with \label, the \write to .aux-file is done delayed.

    Both with \immediatedefinevalue and with \definevalue expansion of the ⟨tokens to deliver when using the value⟩ and expansion of the tokens that form the ⟨name of value⟩ is not prevented at the time of writing data to .aux-file.

The example below provides some hooking into the infrastructure of the LaTeX 2ε-kernel for delivering warning-messages/error-messages in case of values being changed/undefined/multiply defined.

\documentclass[landscape]{article}

\makeatletter
%%=====================================================================================
%% Layout of example document
%%=====================================================================================
\@ifundefined{pagewidth}{}{\pagewidth=\paperwidth}
\@ifundefined{pdfpagewidth}{}{\pdfpagewidth=\paperwidth}
\@ifundefined{pageheight}{}{\pageheight=\paperheight}
\@ifundefined{pdfpageheight}{}{\pdfpageheight=\paperheight}
\textwidth=\paperwidth
\oddsidemargin=2.5cm
\advance\textwidth-2\oddsidemargin
\advance\oddsidemargin-1in
\evensidemargin=\oddsidemargin
\marginparwidth=1.5cm
\marginparsep=.5cm
\parindent=0ex
\parskip=\bigskipamount
\pagestyle{empty}%
%%=====================================================================================
\makeatother

\makeatletter
%%=====================================================================================
%% Switches and helper-macros for triggering error-messages/
%% warnings in case of undefined/multiply defined/changed values
%%=====================================================================================
\newif\if@valueschanged\global\@valueschangedfalse
\newcommand*\@valuesmultiplydefined{}%
\newcommand*\@valuesundefined{}%
\newcommand*\G@valueundefinedtrue{%
  \gdef\@valuesundefined{\@latex@warning@no@line{There were undefined values}}%
}%
%%=====================================================================================
%% \valueundefinederror{<name of value>}
%% Trigger error-message if value is undefined, else do nothing.
%% (Corresponds to \refused of Heiko Oberdiek's refcount-package.)
%%=====================================================================================
\newcommand\valueundefinederror[1]{%
  \@bsphack
  \begingroup
  \@ifundefined{usevalue@#1}{%
    \protect\G@valueundefinedtrue
    \@latex@warning{Value `#1' on page \thepage \space undefined}%
  }{}%
  \endgroup
  \@esphack
}%
%%=====================================================================================
%% \usevalue[{<tokens in case value is undefined>}]{<name of value>}
%%
%% If no optional argument is provided, 
%%   \valueundefinederror{<name of value>}\nfss@text{\reset@font\bfseries??}%
%% is delivered.
%% (Corresponds to \ref of the LaTeX2e-kernel if no optional argument is provided.)
%%=====================================================================================
\@ifdefinable\usevalue{%
  \DeclareRobustCommand\usevalue{\kernel@ifnextchar[{\@usevalue}{\@@usevalue}}%
}%
\@ifdefinable\@@usevalue{%
  \long\def\@@usevalue#1{\usevalueexpandable{#1}{\valueundefinederror{#1}\nfss@text{\reset@font\bfseries??}}}%
}%
\@ifdefinable\@usevalue{\long\def\@usevalue[#1]#2{\usevalueexpandable{#2}{#1}}}%
%%=====================================================================================
%% \usevalueexpandable{<name of value>}{<tokens in case value is undefined>}
%% (Corresponds to \getrefnumber of Heiko Oberdiek's refcount package.)
%%=====================================================================================
\newcommand{\usevalueexpandable}[2]{%
  \@ifundefined{usevalue@#1}{#2}{\csname usevalue@#1\endcsname}%
}%
%%=====================================================================================
%% \immediatedefinevalue{<name of value>}{<tokens to deliver when using the value>}
%% (Almost corresponds to \def\@currentlabel{...}...\label{...} of the LaTeX2e-kernel.
%%  Unlike with \label, the \write is done immediately.)
%%=====================================================================================
\@ifdefinable\immediatedefinevalue{%
  \DeclareRobustCommand{\immediatedefinevalue}{%
    \@definevalue{\immediate\write\@auxout}%
  }%
}%
%%=====================================================================================
%% \definevalue{<name of value>}{<tokens to deliver when using the value>}
%% (Corresponds to \def\@currentlabel{...}...\label{...} of the LaTeX2e-kernel.
%%  Like with \label, the \write is done delayed.)
%=====================================================================================
\@ifdefinable\definevalue{%
  \DeclareRobustCommand{\definevalue}{%
    \@definevalue{\let\thepage\relax\@@definevalue\@auxout}%
   }%
}%
\newcommand\@definevalue[3]{%
    \@bsphack
    \begingroup
    \let\protect\noexpand
    #1{\string\@valuedef{#2}{#3}}%
    \endgroup
    \if@nobreak\ifvmode\nobreak\fi\fi
    \@esphack
}%
\newcommand\@@definevalue[2]{\write#1{\unexpanded\expandafter{\expanded{#2}}}}%
%%%=====================================================================================
%% \@valuedef{<name of value>}
%% (Corresponds to \newlabel of the LaTeX2e-kernel.)
%%%=====================================================================================
\newcommand\@valuedef[1]{\@@valuedef{#1}{usevalue}}%
%%=====================================================================================
%% \@@valuedef{<name of value>}{<prefix for internal macros>}{<tokens to deliver when using the value>}
%% (Corresponds to \@newl@bel / \@testdef of the LaTeX2e-kernel.)
%%=====================================================================================
\newcommand\@@valuedef[3]{%
  \begingroup
  % Hashes were doubled while writing to \@auxout. Let's use a macro for halving them.
  \def\@tempa{#1}%
  \ifx\@newl@bel\@testdef\expandafter\@secondoftwo\else\expandafter\@firstoftwo\fi
  {%
    \@ifundefined{#2@\@tempa}\relax{%
      \gdef\@valuesmultiplydefined{%
        \@latex@warning@no@line{There were multiply-defined values}%
      }%
      \@latex@warning@no@line{Value `\@tempa' multiply defined}%
    }%
    \global\@namedef{#2@\@tempa}{#3}%
  }{%
    \def\reserved@a{#3}%
    \expandafter\ifx\csname#2@\@tempa\endcsname\reserved@a
    \else
      \global\@valueschangedtrue
    \fi
  }%
  \endgroup
}%
%%=====================================================================================
%% This hooks into \@refundefined (which is executed by \enddocument)
%% for delivering messages in case of undefined/multiply defined/changed values:
%%=====================================================================================
\AtEndDocument{%
  \@ifundefined{@refundefined}\gdef\g@addto@macro\@refundefined{\valueschangedmessage}%
}%
\newcommand\valueschangedmessage{%
  \@valuesundefined
  \if@filesw 
  \ifx\@valuesmultiplydefined\@empty
    \if@valueschanged
      \@latex@warning@no@line{Value(s) may have changed. Rerun to get value(s) right}%
    \fi
  \else
    \@valuesmultiplydefined
  \fi
  \fi
}%
%%=====================================================================================
\makeatother

\begin{document}

\fbox{\parbox{\dimexpr\textwidth-2\fboxsep-2\fboxrule\relax}{Let's see the meaning
of the underlying macro:}}

\makeatletter
\verb|\meaning\usevalue@testerhelloworld|: \texttt{\meaning\usevalue@testerhelloworld}
\makeatother

\fbox{\parbox{\dimexpr\textwidth-2\fboxsep-2\fboxrule\relax}{Now let's use the 
unexpandable variant with the optional argument which by default does trigger
(unexpandable) error-messages in case of the value not being defined/available:}}

\underline{Here \texttt{\string\mysuffix} is not yet defined:}

\verb|\usevalue{testerhelloworld}|: \usevalue{testerhelloworld}

\underline{Here \texttt{\string\mysuffix} is defined:}

\def\mysuffix{helloworld}%
\verb|\def\mysuffix{helloworld}| $\to$ \texttt{\string\mysuffix:\ \meaning\mysuffix}

\verb|\usevalue{tester\mysuffix}|: \usevalue{tester\mysuffix}

\fbox{\parbox{\dimexpr\textwidth-2\fboxsep-2\fboxrule\relax}{Now let's use the
expandable variant which does not trigger (unexpandable) error-messages
in case of the value not being defined/available:}}

Trigger the error-message about the value being undefined ``by hand'' if necessary:

\verb|\valueundefinederror{tester\mysuffix}|
\valueundefinederror{tester\mysuffix}

Perform something within an expansion-context where non-expandable things would disturb:

\verb|Value \texttt{tester\mysuffix} is \ifnum\usevalueexpandable{tester\mysuffix}{-1}=-1 un\fi defined.|:\\
Value {\tt tester\string\mysuffix} is \ifnum\usevalueexpandable{tester\mysuffix}{-1}=-1 un\fi defined.

\fbox{\parbox{\dimexpr\textwidth-2\fboxsep-2\fboxrule\relax}{Here the value \texttt{testerhelloworld} is
defined in terms of \texttt{\string\mysuffix}:}}

\verb|\immediatedefinevalue{tester\mysuffix}{42}|%
\immediatedefinevalue{tester\mysuffix}{42}%

\end{document}

enter image description here

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.