7

I am new to Expl3 and would like to be able to use a counter by retrieving its name dynamically, performing this operation within a user command for other stuff. I am unable to display the counter value. I may be making a beginner's mistake, but I don't know where it might be... Here is the minimal example I am working on :

\documentclass{article}

\ExplSyntaxOn

% declare counter
\int_new:N  \g_strxdiv_leveliv_division_count_int
% initialize counter
\int_gset:Nn \g_strxdiv_leveliv_division_count_int { 1 }

% Construct the counter name dynamically
\cs_new:Npn \__strxgen_construct_counter_name:nn 
#1% first variable part
#2% second variable part
{
    g_strx#1_#2_count_int
    % used as-is, \__strxgen_construct_counter_name:nn { div } { leveliv } gives the correct name ('g_strxdiv_leveliv_count_int')
}

% For user purposes
\NewDocumentCommand\Test { m m }
{
    \int_use:c { \__strxgen_construct_counter_name:nn { #1 } { #2 } }
    % <other stuff should be placed here using the counter once "reconstructed">
}

\ExplSyntaxOff


\begin{document}

\Test{div}{leviv}
    % displays the error messg 'You can't use '\relax' after the. (...)' )
    % Thinking it was an expansion issue with \int_use:c, I've tried with \exp_args:... without more success.

\end{document}

Thank you so much for your help.

2 Answers 2

5

Internally, int-type expl3 variables use TeX \count registers, which must be defined before they're used. So something like

\int_use:c { __example_some_int }

will only work if you have previously ran

\int_new:c { __example_some_int }

The obvious solution here is to add \int_new:c to the definition of \__strxgen_construct_counter_name:nn, but that won't work, because \int_new:c is unexpandable, and you can only use expandable commands inside of a :c argument.

An alternate solution is to define a \__strxgen_construct_counter:nn that almost works like the current command, except instead of returning the target csname as a string, it defines a control sequence that points at the same underlying register. So whereas before you could use

\int_use:c { \__strxgen_construct_counter_name:nn { #1 } { #2 } }

you'll now need to use

\__strxgen_construct_counter:nn { #1 } { #2 }
\int_use:N \l__strx_last_counter_int

Complete implementation:

\documentclass{article}

\ExplSyntaxOn

\str_new:N \l__strx_counter_csname_str

\cs_new_protected:Npn \__strxgen_construct_counter:nn #1 #2
{
    \str_set:Nn \l__strx_counter_csname_str { g_strx#1_#2_count_int }
    \int_if_exist:cF { \l__strx_counter_csname_str } {
        \int_new:c { \l__strx_counter_csname_str }
    }
    \cs_set_eq:Nc \l__strx_last_counter_int { \l__strx_counter_csname_str }
}

% For user purposes
\NewDocumentCommand\GetValue { m m }
{
    \__strxgen_construct_counter:nn { #1 } { #2 }
    \int_use:N \l__strx_last_counter_int
}

\NewDocumentCommand\IncrementValue { m m }
{
    \__strxgen_construct_counter:nn { #1 } { #2 }
    \int_incr:N \l__strx_last_counter_int
}

\ExplSyntaxOff

\pagestyle{empty}
\begin{document}
    \verb|\GetValue{div}{leviv}|: \GetValue{div}{leviv}

    \verb|\IncrementValue{div}{leviv}|: \IncrementValue{div}{leviv}

    \verb|\GetValue{div}{leviv}|: \GetValue{div}{leviv}
\end{document}

4

You never defined \g_strxdiv_leviv_count_int, so your \csname...\endcsname command ends up with \relax and that's the reason for the error message.

If you use the counter name you actually allocated, it works.

\documentclass{article}

\ExplSyntaxOn

% declare counter
\int_new:N  \g_strxdiv_leveliv_division_count_int
% initialize counter
\int_gset:Nn \g_strxdiv_leveliv_division_count_int { 1 }

% Construct the counter name dynamically
\cs_new:Npn \__strxgen_construct_counter_name:nn 
#1% first variable part
#2% second variable part
{
    g_strx#1_#2_count_int
}

% For user purposes
\NewDocumentCommand\Test { m m }
{
    \int_use:c { \__strxgen_construct_counter_name:nn { #1 } { #2 } }
    % <other stuff should be placed here using the counter once "reconstructed">
}

\ExplSyntaxOff


\begin{document}

\Test{div}{leveliv_division}

\end{document}

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.