I continue to study expl3 and I do not understand some behavior of user defined function, which returns an integer value (as I thought).

I want to use the integer number returned by \count_number_of_elements:n for further manipulation.

My function \count_number_of_elements:n work well and output correct number if I use it directly. But I need to assign its output to an integer variable. How can I did it?


A more or less real example: "Longest Collatz sequence" from Project Euler problem (but I want to avoid spoilers here)


\int_new:N \l_initial_number_int

\cs_new:Nn \count_number_of_elements:n
    \int_new:N \l_number_int
    \int_set:Nn \l_number_int {1}
    \int_set:Nn \l_initial_number_int {#1}
    {\l_initial_number_int != 1}
    \int_incr:N \l_number_int
    \int_if_even:nTF {\l_initial_number_int}
        {\int_set:Nn \l_initial_number_int {\l_initial_number_int/2} } 
        {\int_set:Nn \l_initial_number_int {3*\l_initial_number_int + 1} }
    \int_use:N \l_number_int

% Code for defining starting number, produces the longest chain. According to my idea, this code should use integer number produced by \count_number_of_elements:n

% say I need get output of \count_number_of_elements:n
\int_set:Nn \l_tmpa_int {\count_number_of_elements:n {#1}}



  • You need it to be expandable. In any case, \int_eval:n is already added to the second argument so \int_add:Nn \l_tmpa_int { 2 + 3 } works (you don't need to use \int_eval:n). – Manuel May 30 '17 at 18:36
  • 1
    @Manuel I suspected this. How can I do expandable? – sergiokapone May 30 '17 at 18:42
  • Well, it depends of what exactly do you want to do with your function, in your example you could just put #1 as the contents of \my_function:n and it would be expandable :) Add a real example case. But it might not be possible to give a general answer unless you clarify what you want to do. – Manuel May 30 '17 at 18:48
  • 1
    \int_set:Nn in your \my_function:n prevents expansion. An assignment is not expandable, so \int_add:Nn \l_tmpa_int {\my_function:n{#1}} in \Number will fail – user31729 May 30 '17 at 18:48
  • 2
    @sergiokapone In tht edited example you have two options: make it expandable; or just remove the \int_use:N \l_number_int from \count_number_of_elements:n and edit \MaxNumber to be \count_number_of_elements:n {#1} \int_set_eq:NN \l_tmpa_int \l_number_int and you are done. – Manuel May 30 '17 at 20:00

There are two possible approaches here. If you want to allow a function to be used 'inside' something like the second argument of \int_set:Nn then it has to be expandable. That means it has to use only other functions which are themselves expandable, which in expl3 means that they are marked in interface3 with a star. So

\cs_new:Npn \my_function:n #1
    \int_eval:n {#1}

will work but

\cs_new:Npn \my_function:n #1  % See below: should be protected
    \int_set:Nn \l_tmpa_tl {#1}
    \int_eval:n {#1}

will not as \int_set:Nn is not marked with a star.

The second approach is needed where you want to use non-expandable functions: you have to arrange to set a variable for return:

\cs_new_protected:Npn \my_function:Nn #1#2
    \int_set:Nn \l_tmpa_int {#2}
    \int_set_eq:NN #1 \l_tmpa_int

(In a real application there would be more going on, of course.)

Note that many problems can be tackled by expansion, though this can get very wearing, depending on the issue at hand. Anything involving typesetting or assignment is specifically excluded: typesetting doesn't have a 'result' by expansion whilst assignments in TeX are not expandable. (If you use LuaTeX you can do assignments in Lua, but then the entire problem is then different.)

Note that you should not be using xparse here: these are code level not document level commands. For that reason, I have used \cs_new:Npn to create expandable code interfaces and \cs_new_protected:Npn for non-expandable ones.

  • I specified my question. I hope it became more clear. – sergiokapone May 30 '17 at 19:41
  • @sergiokapone I'm not sure what I can add for the general case, though if you like I can suggest how I'd tackle the specific problem – Joseph Wright May 30 '17 at 19:48
  • Thank you. I will try it myself. But if I do not succeed in a few days, I will ask for help. – sergiokapone May 30 '17 at 19:52

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.