# How do I get a value out of a group?

I've just recovered from my first real foray into LaTeX3 programming. It was ... an experience. Not a completely unpleasant one and once I'd gotten used to the syntax then I found it a lot easier than it looks. I almost was able to forget that I was programming in a macro language and start thinking in terms of functions and variables again.

Almost.

Where I came up against a brick wall was in the concept of auxiliary functions. I had a main function that did a lot of work. I would quite like to have farmed off parts of it to some other functions, as much for keeping track of what was going on as anything else. But I couldn't work out how to do that separation properly.

Here's an example. Suppose I wanted to compute the Euclidean length of a lot of 2-vectors. In, say, lua then I might write:

function veclen(a,b)
return math.sqrt(a^2 + b^2)
end


Now that isn't directly comparable with a LaTeX3 "function" so let me pretend that I can't write inline formulae in lua and write it out a bit more like LaTeX3.

function veclen(a,b)
local s = a
local t = b
multiply(s,s)
multiply(t,t)
sqrt(s)
return s
end


Here, multiply and add are functions that "do what they say on the tin" but, crucially, instead of returning a value they store the answer in the first variable.

That's fairly similar to my LaTeX3 function:

\cs_new:Nn \fp_veclen:NNN {
\fp_set_eq:NN \l_hobby_veclena_fp #2
\fp_set_eq:NN \l_hobby_veclenb_fp #3
\fp_mul:Nn \l_hobby_veclena_fp {\l_hobby_veclena_fp}
\fp_mul:Nn \l_hobby_veclenb_fp {\l_hobby_veclenb_fp}
\fp_pow:Nn \l_hobby_veclena_fp {.5}
\fp_set_eq:NN #1 \l_hobby_veclena_fp
}


In the lua function, a and b are local but even if they are not then the commands local s = a and local t = b force them to be local. But the return s breaks out of the function scope and makes the answer available at the next level up. In doing this in TeX, I'd do all my computations inside a group: something like:

\cs_new:Nn \fp_veclen:NNN {
\group_begin:
\fp_set_eq:NN \l_hobby_veclena_fp #2
\fp_set_eq:NN \l_hobby_veclenb_fp #3
\fp_mul:Nn \l_hobby_veclena_fp {\l_hobby_veclena_fp}
\fp_mul:Nn \l_hobby_veclenb_fp {\l_hobby_veclenb_fp}
\fp_pow:Nn \l_hobby_veclena_fp {.5}
\group_end:
\fp_set_eq:NN #1 \l_hobby_veclena_fp
}


Except that that wouldn't work: if I put the \group_end: where I have done so then \l_hobby_veclena_fp has lost its value. If I put it after the assignment then the assignment is local to the group and so is lost moments later.

To cut a long story short: I want the computation to be local so that I can use my temporary variables with impunity, but I need the assignment to be outside the computation group (but not global) so that it can be used by the calling code.

How do I do this? Obviously it is possible because the LaTeX3 functions must do this all the time. TikZ uses "smuggling" to do this: define a temporary global variable to be the answer and then outside the group make the assignment which makes the actual assignment not global but outside the computation group: \global\let\tikz@smuggle=\the@answer\endgroup\let\the@answer=\tikz@smuggle. What's the right LaTeX3-way to do this?

For bonus points, there's another small issue with scoping. In the lua function, the variables a and b were already local: I could reassign them with impunity. In TeX, that's not so easy. If I do something like

\fp_set_eq:NN \l_my_tmpa_fp #1
\fp_set_eq:NN \l_my_tmpb_fp #2


then there's always the danger that I called my function with \calc:NN \l_my_tmpb_fp \l_my_tmpa_fp. How do I make local aliases for my incoming variables without defining a new set of temporary macros for every single function?

 I know I could look at the LaTeX3 code - indeed I took a quick glance and got a vague idea, but I suspect that there would be subtleties I'd miss by not asking, and I hope that others will benefit from a more public answer and explanation.

• You can use \fp_gset_eq:NN #1 \l_hobby_veclena_fp inside the group. May 17, 2012 at 19:28
• @MarcoDaniel But that globally sets whatever-#1-was to \l_hobby_veclena_fp. But #1 was (or could have been) only a local variable in the calling function. So it might have another global value that I don't want to touch. May 17, 2012 at 19:36
• Why not use the TikZ way? Seems nice'n'easy to me... May 17, 2012 at 19:42
• @cgnieder: I believe in the separation of TikZ and LaTeX3. Seriously, if there's a "proper l3 way" to do this, I'd like to know about it. May 17, 2012 at 19:46
• You can use: \edef\@tempa{\endgroup\value=\the\value\relax}\@tempa to move a value (counter, length) out of a group. Don't ask me how to translated that into Klingon, aeh, LaTeX3. The same is possible for macros: \edef\@tempa{\endgroup\def\noexpand\mymacro{\mymacro}}\@tempa or, if you don't want to expand it all the way: \def\@tempa{\endgroup\def\noexpand\mymacro{\unexpanded\expandafter{\mymacro}}}\@tempa, or without e-TeX: \expandafter\endgroup\expandafter\def\expandafter\mymacro\expandafter{\mymacro}. The first two values also work nicely with multiple macros/registers. May 17, 2012 at 20:19

# Soln 1

This might be considered overkill, but I once wrote a function \group_after_set:NNn to provide an "abstraction" to handle this, used as in:

\group_begin:
\group_begin:
\group_after_set:NNn \int_set:Nn \y {3}
% \y == 3
\group_end:
% \y == 3
\group_end:
% \y == undefined


I quite like it but I don't know if should be added to expl3 or not. Suggestions?

The advantage over this approach is that you can use it multiple times within a group to "export" multiple variables, unlike Enrico's answer which is much more simple and efficient for the common case.

Anyway, here it is:

\documentclass{article}
\usepackage{expl3}
\begin{document}
\ExplSyntaxOn
\cs_if_free:NT \group_insert_after:N
{
\cs_set_eq:NN \group_insert_after:N \group_execute_after:N
}

\cs_generate_variant:Nn \tl_if_empty:nT {v}
\cs_generate_variant:Nn \tl_show:N {v}
\cs_new:Nn \group_after_set:NNn
{
% set the variable locally for use inside the group:
#1 #2 {#3}

\cs_if_exist:cF { g_aftergroup_ \int_use:N \etex_currentgrouplevel:D _tl }
{
\tl_new:c { g_aftergroup_ \int_use:N \etex_currentgrouplevel:D _tl }
}

% first time the function is executed inside the group:
\tl_if_empty:vT { g_aftergroup_ \int_use:N \etex_currentgrouplevel:D _tl }
{
% set up the aftergroup execution:
\group_insert_after:c
{ g_aftergroup_ \int_use:N \etex_currentgrouplevel:D _tl }

% reset the material for aftergroup execution:
\tl_gset:cx { g_aftergroup_ \int_use:N \etex_currentgrouplevel:D _tl }
{
\tl_gclear:c { g_aftergroup_ \int_use:N \etex_currentgrouplevel:D _tl }
}
}

% append the new material to the aftergroup execution:
\tl_gput_right:cx
{ g_aftergroup_ \int_use:N \etex_currentgrouplevel:D _tl }
{
\exp_not:n { #1 #2 } { \exp_not:V #2 }
}
}

\cs_generate_variant:Nn \group_insert_after:N {c}

\int_new:N \y
\int_new:N \yy

\cs_generate_variant:Nn \tl_if_eq:nnF {V}
\cs_new:Nn \assert:Nn
{
\tl_if_eq:VnF #1 {#2} {[ERROR:\tl_to_str:n{#1~!=~#2}]}
}

\group_begin:
\group_after_set:NNn \tl_set:Nn \x {xx}
\group_after_set:NNn \tl_set:Nn \xx {x}
\assert:Nn \x {xx}
\assert:Nn \xx {x}
\group_begin:
\group_after_set:NNn \int_set:Nn \y {3}
\group_after_set:NNn \int_set:Nn \yy {2}
\assert:Nn \y  {3}
\assert:Nn \yy {2}
\group_end:
\assert:Nn \x {xx}
\assert:Nn \xx {x}
\assert:Nn \y  {3}
\assert:Nn \yy {2}

% check repeated doesn't break anything:
\group_begin:
\int_set:Nn \y  {6}
\int_set:Nn \yy {5}
\group_end:
\assert:Nn \x {xx}
\assert:Nn \xx {x}
\assert:Nn \y  {3}
\assert:Nn \yy {2}
\group_end:

\assert:Nn \x {xx}
\assert:Nn \xx {x}
\assert:Nn \y  {0}
\assert:Nn \yy {0}

\ExplSyntaxOff
\end{document}


From some discussion elsewhere on this page with Ahmed, it's become clear to me that the syntax introduced about isn't such a great idea. For example, if you want to set a variable using tl_set:Nx, it's not then appropriate to use that same function to define the variable outside the group. Really what we're looking for is an extension of etextool's \AfterGroup that permits easy expansion control (which is part of the whole design philosophy of expl3).

So separating the local and "group escaped" variables need to be done independently, syntax-wise. Here's a modified implementation of the above that does this. The code looks similar:

\int_new:N \y
\group_begin:
\group_begin:
\int_set:Nn \y {3}
\group_var_return:NN \int_set:Nn \y
% \y == 3
\group_end:
% \y == 3
\group_end:
% \y == 0


Note that since we don't have a mapping between variable types and their setting functions, in this case \int_set:Nn is required twice. This isn't so bad, really, since you could in theory use this for all sorts of setting functions. So the "general" approach here I've written as follows:

\clist_new:N \z
% ...

\group_begin:
% let's say we're in a macro right now that processes
% some input argument and saves the result to "\y".
\do_something_with:Nn \y {#1}
\group_after_insert:nV { \clist_put_right:Nn \z } { \y }
\group_end:


So it's easy to see how the former (\group_var_return:NN) is just something like \group_after_insert:nV { \int_set:Nn \y } \y. Whether these levels of abstraction are necessary or helpful is a bit of an open question. I'm inclined to think that at least the \group_var_return:NN one looks good.

Here is the implementation of all that:

\documentclass{article}
\usepackage{expl3}
\begin{document}
\ExplSyntaxOn

\cs_if_free:NT \group_insert_after:N
{
\cs_set_eq:NN \group_insert_after:N \group_execute_after:N
}

\cs_generate_variant:Nn \tl_if_empty:nT {v}
\cs_generate_variant:Nn \group_insert_after:N {c}

\cs_new:Nn \group_after_insert:nn
{
\cs_if_exist:cF { g_aftergroup_ \int_use:N \etex_currentgrouplevel:D _tl }
{
\tl_new:c { g_aftergroup_ \int_use:N \etex_currentgrouplevel:D _tl }
}

% first time the function is executed inside the group:
\tl_if_empty:vT { g_aftergroup_ \int_use:N \etex_currentgrouplevel:D _tl }
{
% set up the aftergroup execution:
\group_insert_after:c
{ g_aftergroup_ \int_use:N \etex_currentgrouplevel:D _tl }

% reset the material for aftergroup execution:
\tl_gset:cx { g_aftergroup_ \int_use:N \etex_currentgrouplevel:D _tl }
{
\tl_gclear:c { g_aftergroup_ \int_use:N \etex_currentgrouplevel:D _tl }
}
}

% append the new material to the aftergroup execution:
\tl_gput_right:cx
{ g_aftergroup_ \int_use:N \etex_currentgrouplevel:D _tl }
{
\exp_not:n { #1 {#2} }
}
}

\cs_generate_variant:Nn \group_after_insert:nn {nV}

\cs_new:Npn \group_var_return:NN #1 #2
{
\group_after_insert:nV { #1 #2  } { #2 }
}

\int_new:N \y
\int_new:N \yy

\cs_generate_variant:Nn \tl_if_eq:nnF {V}
\cs_new:Nn \assert:Nn
{
\tl_if_eq:VnF #1 {#2} {[ERROR:\tl_to_str:n{#1~!=~#2}]}
}

\group_begin:
\tl_set:Nn \x {xx}
\tl_set:Nn \xx {x}
\group_after_insert:nV { \tl_set:Nn \x  } { \x  }
\group_after_insert:nV { \tl_set:Nn \xx } { \xx }
\assert:Nn \x {xx}
\assert:Nn \xx {x}
\group_begin:
\int_set:Nn \y {3}
\int_set:Nn \yy {2}
\group_var_return:NN \int_set:Nn \y
\group_var_return:NN \int_set:Nn \yy
\assert:Nn \y  {3}
\assert:Nn \yy {2}
\group_end:
\assert:Nn \x {xx}
\assert:Nn \xx {x}
\assert:Nn \y  {3}
\assert:Nn \yy {2}

% check repeated doesn't break anything:
\group_begin:
\int_set:Nn \y  {6}
\int_set:Nn \yy {5}
\group_end:
\assert:Nn \x {xx}
\assert:Nn \xx {x}
\assert:Nn \y  {3}
\assert:Nn \yy {2}
\group_end:

\assert:Nn \x {xx}
\assert:Nn \xx {x}
\assert:Nn \y  {0}
\assert:Nn \yy {0}

\ExplSyntaxOff
\end{document}

• I vote for implementation ;-) May 17, 2012 at 21:51
• Obviously \group_after_set:Nn isn't the best name for the thing, though. May 17, 2012 at 23:56
• Gets my vote, and floats my boat, and doesn't get my goat (I'll get my coat). May 18, 2012 at 5:36
• @WillRobertson: If this is all about eTeX's \currentgrouptype, please have you simply used the returned number (0,16)? I am sorry, I don't do LaTeX3 at all; I am sure you know that. In the past I have had trouble getting out of deep groups (for error recovery) using \currentgrouptype. I can ask a separate question if that will help. May 18, 2012 at 14:44
• I like \group_var_return:NN. Consider it stolen^H^H^H^H^H^Hcopied. May 24, 2012 at 7:44

With the new FPU, we can avoid the group entirely in this particular case (for the more general 'escape from a group' question, see the answer by egreg).

\cs_new_protected:Npn \fp_veclen:NNN #1#2#3
{
\fp_set:Nn #1
{
( ( #2 ) ^ 2 + ( #3 ) ^ 2 ) ^ ( 0.5 )
}
}


(At the time of writing, this needs the development version of expl3 rather than the CTAN release.)

On the 'bonus' part to the question, I'd simply pass the values using V-type expansion. TeX grouping does not work like Lua grouping, so you can't group in the way you'd like.

• Thanks for the V. And I've missed not being able to use expressions for fp stuff so I'm looking forward to that being in the official version. May 18, 2012 at 5:35

You simply have to get the value of the variable before closing the group; since you have to skip three tokens, \exp_args:NNNV is what you need:

\cs_new_protected:Npn \fp_veclen:NNN #1 #2 #3
{
\group_begin:
\fp_set_eq:NN \l_hobby_veclena_fp #2
\fp_set_eq:NN \l_hobby_veclenb_fp #3
\fp_mul:Nn \l_hobby_veclena_fp {\l_hobby_veclena_fp}
\fp_mul:Nn \l_hobby_veclenb_fp {\l_hobby_veclenb_fp}
\fp_pow:Nn \l_hobby_veclena_fp {.5}
\exp_args:NNNV \group_end: \fp_set:Nn #1 \l_hobby_veclena_fp
}


As Joseph remarks in a comment this should be protected, being not expandable; the Npn variety is more efficient.

If more variables have to be set outside the group, a different method must be used (waiting for Will's proposal to be implemented); the last line in the definition can become

\use:x
{
\group:end
\fp_set:Nn \exp_not:N #1 { \l_hobby_veclena_fp }
% other similar assignments
}


(Thanks to Joseph Wright and Marco Daniel for remarking it.)

Note that \fp_veclen:Nnn should have this signature if you plan to call it as \fp_veclen:Nnn \l_hobby_veclen_fp {2}{3}. Also \fp_set_eq:NN should be \fp_set:Nn.

• This should be \cs_new_protected as it's not expandable; I'd also favour \cs_new_protected:Npn. May 17, 2012 at 21:30
• @MarcoDaniel I've added the remark; as I wrote, this can be particularly useful when more than one assignment has to be performed "outside the group". May 18, 2012 at 10:31

Will Robertson has sent me an eTeX translation of this LaTeX3 solution, which I have adapted substantially. The difference between Will's and Martin Scharrer's solutions is that Martin's scheme deals with only one type of group (semi simple group). See also etextools's \AfterGroup, which works for all groups but doesn't accumulate code as Will's scheme does.

\documentclass{article}
\usepackage{catoptions}
\makeatletter
% The star (*) variant executes code #1 within the group. #1 must be
% executable in this case. The un-starred version simply takes the
% material outside the group.
\robust@def*\aftergroupexecute{\cpt@testst\cpt@aftergroupexecute}
\robust@def\cpt@aftergroupexecute#1{%
\ifboolTF{cpt@st}{#1}{}%
% \ag@elt is local to current group:
\def\ag@elt{aftergroup@execute@\romannumeral\currentgrouplevel}%
\ifcsndefTF\ag@elt{}{%
\aftercsname\aftergroup\ag@elt
% for post \aftergroup resetting:
\csn@xdef\ag@elt{\gundefcsn{\ag@elt}}%
}%
\csn@xdef\ag@elt{\expandcsnonce\ag@elt\unexpanded{#1}}%
}
\makeatother
% Tests
\begin{document}
\def\x{FOO}
\def\y{ZOO}
\begingroup
\begingroup
\hbox{%
\vbox to 5cm{%
$\aftergroupexecute{\def\x{foo}}% \aftergroupexecute{\def\y{zoo}}%$
%\show\x
\show\y
}%
\show\x
}%
\show\x
\endgroup
\show\x
\endgroup
\show\x
\end{document}


EDIT

Will, Please how will your scheme work in the following scenario? This isn't a debate; my aim is to understand your scheme. I want only \includelater and \somemasters outside the adjusted hbox group.

\hbox{%
\def\classlist{David/Salomon, Michael/Downes, Frank/Mittelbach, David/Carlisle,
David/Kastrup, Heiko/Oberdiek, Till/Tantau, Donald/Arseneau, Joseph/Wright,
Hans/Hagen, Taco/Hoekwater, Hartmut/Henkel, Robin/Fairbain, Ulrike/Fischer,
Ulrich/Diez}
% Let Will's processing function be \do:
\def\do#1/#2,{%
\ifx\do#1\else
\noexpand\elt{\cpttrimspace{#1}}{\cpttrimspace{#2}}%
\expandafter\do
\fi
}%
\edef\classlist{\expandafter\do\classlist,\do/,}%
\aftergroupexecute{\def\includelater{Will Robertson}}
\expandafter\aftergroupexecute\expandafter{\expandafter\def\expandafter
\somemasters\expandafter{\classlist}}
}
%\show\includelater
\show\somemasters

• A disadvantage to this syntax IMO is that what is in \aftergroupexecute still needs to be expanded if you're passing out results of a calculation. E.g., foo must still consist of non-local material. May 21, 2012 at 6:14
• @WillRobertson: I am afraid I don't understand your comment. Perhaps you could send me an email. In the meantime, in the example given, with the *-variant you have the option of executing \def\x{foo} (or any given <code>) within the local group, or simply passing it on to outside the group. In your approach, you hardwired \def#1{#2}, implying that only the definition of #1 could take place within and outside the group. May 21, 2012 at 7:24
• Let's say you want to take some input and process it using a scratch variable, then output it in \x. So you're writing something like \begingroup \def\@tempa{#1} \processingfunction \y {«something with \@tempa»} \aftergroupexecute{ \def\x{\y} } \endgroup. How do you get \x defined as \y without doing yet more ugly expansion control? May 21, 2012 at 7:45
• To be fair I don't think my syntax is perfect either. I now think it's better to separate local assignment and the declaration of "returning" a variable. So if I re-wrote my answer now I'd prefer a syntax like \group_return_variable:N \x where the local value of \x would remain after the group ended. May 22, 2012 at 2:11
• Well, I don't know LaTeX3, but \begingroup\def\foo{foo}\aftergroup\foo\endgroup, of course, won't work. May 22, 2012 at 3:52

Now with functional package (which is based on expl3) we can do programming in a way similar to Lua language. Note that \Result command collects the return value and passes it out of the function group.

-- lua code for comparison --
function veclen(a,b)
return math.sqrt(a^2 + b^2)
end

\documentclass{article}
\usepackage{functional}
\Functional{scoping=true} % make every function become a group
\begin{document}

\IgnoreSpacesOn
\PrgNewFunction \veclen { M M } {
\Result { \FpEval { ( (#1)^2 + (#2)^2 ) ^ (0.5) } }
}
\FpSet \lTmpaFp {1.2}
\FpSet \lTmpbFp {3.4}
\veclen \lTmpaFp \lTmpbFp
\IgnoreSpacesOff

\end{document}


And changes to the local variables are reset out of the function.

\documentclass{article}
\usepackage{functional}
\Functional{scoping=true} % make every function become a group
\begin{document}

\IgnoreSpacesOn
\PrgNewFunction \veclenx { M M } {
\FpSet #1 {-1.2}
\FpSet #2 {-3.4}
\Result { \FpEval { ( (#1)^2 + (#2)^2 ) ^ (0.5) } }
}
\IgnoreSpacesOff

\FpSet \lTmpaFp {1.2}
\FpSet \lTmpbFp {3.4}
\veclenx \lTmpaFp \lTmpbFp

\string\lTmpaFp{} = \FpUse \lTmpaFp,
\string\lTmpbFp{} = \FpUse \lTmpbFp.

\end{document} 