2

Consider this example:

\documentclass{article}
\begin{document}
\def\something{something}
\something

    {
        \def\something{another thing}

      \something
    }

    \something
\end{document}

From the output it can be seen that there are two variables something each living in their own scope:

enter image description here

Now, I put a variable to live inside a newcommand:

\documentclass{article}
\def\something{something}
\newcommand{\dosomething}{
  invoking ``dosomething''
  \def\something{another thing}

  \something
}
\begin{document}
\something

\dosomething

\something
\end{document}

From output it can be seen that invoking the newcommand altered the previous definition of the variable:

enter image description here

This can lead to obscure errors particularly with libraries involving hundreds of variables. Is there a way to protect my variables from being altered by newcommands? What is the best approach?

  • 3
    Well, in the second example you have no group. \newcommand does not create a group by itself. You could do \newcommand{\dosomething}{{...}}. – campa Dec 2 '19 at 10:42
  • 2
    a macro is just expanded inline essentially as a textual replacement, it implies no grouping itself. You can of course define the replacement text of the command to include a group, But mixing \def and \newcommand in the same code is likely to lead to obscure errors clearer to stick to primitive constructs or latex ones, not a mixture of the two. – David Carlisle Dec 2 '19 at 11:14
  • @campa better to use the more explicit \begingroup and \endgroup, imho. – Skillmon likes topanswers.xyz Dec 2 '19 at 11:14
  • Your macros can have names from which you can see what they (are intended to) do. E.g., instead of \dosomething you could name the thing \WithinTheCurrentScopeTurnSomethingIntoAnotherThing. At first glimpse long macro names which have a semantical aspect as they explain what the thing does seem cumbersome. But they can be very nice when the need of debugging arises. – Ulrich Diez Dec 2 '19 at 20:27
  • By default (re)definitions in terms of \newcommand/\renewcommand apply to the current scope. In order to prevent this make sure that another local scope is opened up before the (re)definition-assignments in question are carried out. E.g., by means of \begingroup..\endgroup or {..} or \bgroup..\egroup. In case you wish (re)definitions in terms of \(re)newcommand to apply to all superordinate scopes also, look at the package letltxmacro, especially the command \GlobalLetLtxMacro. – Ulrich Diez Dec 2 '19 at 20:38
3

TeX offers a macro expansion mechanism; the macro is replaced by the replacement text. Therefore, with your current definition

\newcommand{\dosomething}{
  invoking ``dosomething''
  \def\something{another thing}

  \something
}

the document

\begin{document}
\something

\dosomething

\something
\end{document}

is effectively equivalent to

\begin{document}
\something

invoking ``dosomething''
\def\something{another thing}

\something

\something
\end{document}

(plus a couple of trailing spaces you have been somewhat careless about :-))

If you want changes to \something to be restricted to the execution of \dosomething you must include a level of grouping, either with explicit braces {...} or (more readable) with the primitives \begingroup/\endgroup

\newcommand{\dosomething}{% <-- don't forget this
  \begingroup
  invoking ``dosomething''%
  \def\something{another thing}%

  \something
  \endgroup
}
| improve this answer | |

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.