TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have a scenario where I'm testing for a condition within a group which will then trigger inputting a corresponding outside file. The problem is that the outside file may contain control sequences that I later need. I tried to make sure the expansion was going to happen after closing the group as in the following example. (I've omitted the testing condition because this example nevertheless duplicates my error.)

\begin{filecontents}{anotherfile}
\def\aemoon{This is the moon}
This is my other file.
\end{filecontents}

\documentclass{article}

\begin{document}

Testing

\begingroup
  \def\helloworld{\input{anotherfile}}
  \expandafter\helloworld
\endgroup

\aemoon

\end{document}

But this results in an error

! Undefined control sequence.
l.17 \aemoon

The same thing happens below where there's no need to input an outside file

\documentclass{article}
\begin{document}

Testing

\begingroup
  \def\helloworld{\newcommand\aemoon{this is the moon}}
  \expandafter\helloworld
\endgroup

\aemoon

\end{document}

In either example, I was expecting that the command \aemoon was getting defined outside of the group on account of \expandafter. (\aftergroup will clearly not work since after the group \helloworld has not been defined.)

Thinking back to my original situation where I'm inputting another file, I know I could write something like

\begin{filecontents}{anotherfile}
\def\aemoon{This is the moon}
This is my other file.
\end{filecontents}

\documentclass{article}

\begin{document}

Testing

\begingroup
  \gdef\helloworld{\input{anotherfile}}
\endgroup
\helloworld

\aemoon

\end{document}

So, I do have a work around. But I would like to know why the first two examples are not working because my understanding is that the expansion should be happening outside the group, but...

So, what is happening here?

share|improve this question
    
I'm not sure what would be the reason for the group. Can you think of one? – egreg Jan 8 at 19:08
    
@egreg In this MWE there's no need except to create the situation I'm facing. In the real deal, I'm doing a number of tests etc. and defining a number of temporary control sequences for this and that for which I felt a group was the ideal way to proceed. But then I needed a way of getting some information out of the group in a context where definitions may not be global. – A.Ellett Jan 8 at 19:41
1  
Be careful that with Hood Chatham's (good) technique, you only get the first level expansion of \helloworld and then the group ends, destroying all assignments made inside it. So, if you say \begingroup\ifbla\def\foo{bla}\else\def\foo{bar}\fi\def\gnu{A \foo}\expandafter\endgroup\gnu you'll be in trouble. – egreg Jan 8 at 22:08
    
@egreg Good point. Nothing of the sort will happen since mostly the machinations inside the group are to determine which file to input. – A.Ellett Jan 8 at 23:42
up vote 11 down vote accepted

You should say:

\begingroup
  \def\helloworld{\newcommand\aemoon{this is the moon}}
  \expandafter
\endgroup\helloworld

The idea here is that the \expandafter causes \helloworld to be expanded before TeX sees the \endgroup, so first \helloworld gets expanded and TeX sees \endgroup\newcommand\aemoon{this is the moon}. Then it evaluates the \endgroup and \helloworld goes out of scope, then it evaluates the \newcommand and \aemoon is defined.

You probably confused this situation with the case where there's a command in a conditional that takes an argument, and you don't want it to use \fi or \else and the false clause as its argument so you say: \ifsomething \expandafter\somecommand\fi. Since \else and \fi are fully expandable and when expanded delete themselves (and in the case of \else the false clause), this fixes that problem.

The problem with saying \expandafter\helloworld\endgroup is that \endgroup is not expandable, so the result is the \expandafter expands the \endgroup, which changes it not at all -- \endgroup acts like a } here. Then what TeX sees is \mycommand\endgroup, which doesn't do what you want.

Roughly speaking, TeX has two stages of evaluation -- expansion, where it takes macros and repeatedly expands them, and evaluation, where it takes unexpandable primitives (either characters or commands like \bgroup, \relax, \def, \show etc) and evaluates them. \expandafter only interacts with the expansion stage. Many nonintuitive behaviors of TeX result from this expansion evaluation distinction.

However, even if \expandafter\helloworld\egroup did behave as you expected, it would not be right, because that would then be the same as saying \egroup\helloworld, which would cause an error because the definition of \helloworld went out of scope.

share|improve this answer
    
Very nice. This is a solution. But, it still leaves my question unanswered. Why is \expandafter\helloworld\endgroup not doing what I think it should be? – A.Ellett Jan 8 at 18:47
    
That is definitely the case I was thinking of. – A.Ellett Jan 8 at 18:55
    
I'll try to add a bit more detail as to why they are different -- it's actually quite subtle and confusing. – Hood Chatham Jan 8 at 18:57
    
Thank you for your very informative explanation. – A.Ellett Jan 8 at 20:01

\endgroup is not expandable, which makes

\begingroup
  \def\helloworld{\newcommand\aemoon{this is the moon}}
  \expandafter\helloworld
\endgroup

equivalent to

\begingroup
  \def\helloworld{\newcommand\aemoon{this is the moon}}
  \helloworld
\endgroup

As such, \helloworld is defined, executed and then everything within the group that isn't \global does not survive. This includes \aemoon. You may consider an alternative

\begingroup
  \def\helloworld{\endgroup\newcommand\aemoon{this is the moon}}
  \helloworld

where \helloworld ends the group implicitly, leaving \aemoon still defined.

share|improve this answer
    
Hmmm. I like this approach. – A.Ellett Jan 8 at 19:02
    
@A.Ellett: The approach is similar to the commonly-used \begingroup \edef\x{\endgroup <xxx>}\x technique to expand <xxx> but not keep the definition of \x. – Werner Jan 8 at 19:05
    
which is exactly why I like it so much – A.Ellett Jan 8 at 23:43
   \expandafter\helloworld\endgroup

applies \expandafter to \endgroup that is not an error but it does nothing as \endgroup is not expandable so it is equivalent to

  \helloworld\endgroup

So \helloworld acting inside the group is the expected behaviour.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.