5

Here's the question: why does the following code reset the meaning of the \pgPtList control sequence when the group ends?

\documentclass[12pt]{article}

\begin{document}

\begingroup
    \gdef\pgPtList{}
    \edef\pgPtList{8}
    pgPtList is: \pgPtList
    
    \edef\pgPtList{8, 5}
    pgPtList is: \pgPtList
\endgroup

Empty environment has ended.

pgPtList is: \pgPtList

\end{document}

Here's the output it produces:

pgPtList is: 8
pgPtList is: 8, 5
Empty environment has ended.
pgPtList is:

My current understanding is that this has something to do with how groups work, so a likely follow-up question is this: how can I redefine the control sequence such that the change sticks once the group ends?

Here's the broader context: I'm trying to typeset an exam and track the number of points on each page, and I'm continually updating \pgPtList to keep track of how many points are on each page. At the each of the exam, \pgPtList acts as a default parameter to another command that creates a table of point values.

The points on each page are updated within an enumerate environment, which is why the \begingroup and \endgroup are present in the reprex. Ideally, I'd like to be able to update the \pgPtList variable within this environment, even though the point table command will be called outside of it.

My main point of confusion is around \edef and \gdef. My naive understanding is that these commands are meant to make the resulting control sequences accessible outside of the current group, but the output I get from the code above suggests that something else is happening.

2
  • 2
    Welcome! Use \xdef rather than \edef. \edef is local, just as \def is. \xdef is global, just as \gdef is. Note that the \gdef definition does survive the group - you don't get an error due to an undefined control sequence. But all your later (re)definitions are local.
    – cfr
    Commented Dec 21, 2023 at 2:39
  • If you are tracking points, you may be better off using a counter rather than commands. If you use a LaTeX counter, it will be global out-of-the-box and you can use calculations to update it e.g. \addtocounter{mycounter}{2} or whatever.
    – cfr
    Commented Dec 21, 2023 at 3:22

1 Answer 1

5
  • \def\macroname<argument specification>{definition} is a local, standard definition;
  • \edef\macroname<argument specification>{definition} is a local, expanded definition i.e. definition is expanded before assigning \macroname;
  • \gdef\macroname<argument specification>{definition} is a global, standard definition;
  • \xdef\macroname<argument specification>{definition} is a global, expanded definition.

In your case, the initial definition \gdef\pgPtList{} does survive the local group. If it did not the use of \pgPtList after \endgroup would result in an error.

However, all subsequent (re)definitions of \pgPtList are explicitly local, so those changes do not survive after \endgroup and the meaning of \pgPtList reverts to the initial empty definition.

The following example may be helpful:

\documentclass[12pt]{article}

\begin{document}

\newcounter{tweak}
\setcounter{tweak}{0}
\def\rstatement{Redefinition \thetweak.}

\begingroup
  \gdef\pgPtList{Initial, global definition.}
  pgPtList is: \pgPtList
  
  \edef\pgPtList{\rstatement}
  pgPtList is: \pgPtList ; \stepcounter{tweak}\pgPtList
  
  \def\pgPtList{\rstatement}
  pgPtList is: \pgPtList ; \stepcounter{tweak}\pgPtList
\endgroup

Environment has ended.

pgPtList is: \pgPtList

\begingroup
  \xdef\pgPtList{\rstatement}
  pgPtList is: \pgPtList ; \stepcounter{tweak}\pgPtList
\endgroup

Environment has ended.

pgPtList is: \pgPtList

\begingroup
  \gdef\pgPtList{\rstatement}
  pgPtList is: \pgPtList ; \stepcounter{tweak}\pgPtList
\endgroup

Environment has ended.

pgPtList is: \pgPtList

\end{document}

output illustrating local/global & expanded/standard macro definitions

Note that \def and \gdef ensure \pgPtList uses the value of the counter tweak when the macro \pgPtList is used, which might not be the value at the time of definition.

In contrast, \edef and \xdef ensure \pgfPtList uses the value of the counter tweak at the time of definition, even if the value has changed in the meantime.

On the other hand, both \def and \edef are local definitions. Their effect ends when then current group ends.

In contrast, \gdef and \xdef are global. They are effective unless and until some subsequent definition of \pgfPtList supersedes them, irrespective of grouping.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .