Mysterious horizontal space when using \label after beginning a user-defined environment

This is the case because \label was created in such a way that it doesn't introduce a second white space after it and doesn't change the spacefactor (a TeX internal variable which specifies how much the current space might be stretched to get alignment, it is set dependent on the last character prior to that space). This is done by \@bsphack and \@esphack. Unfortunately this ends the scope of \ignorespaces as there was a non-space token, and the space after \label{} is in fact inserted because there was no space prior to \label (else there would be an \ignorespaces inserted by \@esphack).

The following checks whether exercise is followed by a \label and if so eats the space after \label{}:

\documentclass{article}
\RequirePackage{expl3}
\RequirePackage{xparse}

\ExplSyntaxOn
\makeatletter
\newcounter{exercise}
\NewDocumentEnvironment{exercise}{}
{
  \refstepcounter{exercise}
  \par\noindent
  \theexercise.\hspace{4pt}X
  \@ifnextchar\label
    {\eatlabel}{\ignorespaces}
}
{
  \par
  \ignorespacesafterend
}
\newcommand\eatlabel{}
\def\eatlabel\label#1{\label{#1}\ignorespaces}
\makeatother
\ExplSyntaxOff

\begin{document}

\begin{exercise}
  If $H$ is a subgroup of $G$, then something.
\end{exercise}

\begin{exercise} \label{A}
  If $H$ is a subgroup of $G$, then something.
\end{exercise}

\end{document}

enter image description here


You have to delay the typesetting until possibly \label has appeared. Assuming these exercises aren't inside lists, the simplest way is using \everypar.

\documentclass{article}
\usepackage{expl3}
\usepackage{xparse}
\usepackage{showframe}

\ExplSyntaxOn
\newcounter{exercise}
\NewDocumentEnvironment{exercise}{}
 {
  \refstepcounter{exercise}
  \par
  \everypar={{\setbox0=\lastbox}\theexercise.\hspace{4pt}\everypar={}}
 }
 {
  \par
  \ignorespacesafterend
 }
\ExplSyntaxOff

\begin{document}

\begin{exercise}
  If $H$ is a subgroup of $G$, then something.
\end{exercise}

\begin{exercise}\label{A}
  If $H$ is a subgroup of $G$, then something.
\end{exercise}

\end{document}

enter image description here

With {\setbox0=\lastbox} we remove the indentation box; since \label doesn't start a paragraph, the space after it is ignored.

Possibly simpler: use a theorem-like environment.

\documentclass{article}
\usepackage{amsthm}
\usepackage{showframe}

\newtheoremstyle{exercise}
  {0pt}       % ABOVESPACE
  {0pt}       % BELOWSPACE
  {\upshape}  % BODYFONT
  {0pt}       % INDENT (empty value is the same as 0pt)
  {}          % HEADFONT
  {.}         % HEADPUNCT
  { }         % HEADSPACE
  % CUSTOM-HEAD-SPEC follows
  {\thmnumber{#2}}

\theoremstyle{exercise}
\newtheorem{exercise}{}

\begin{document}

\begin{exercise}
  If $H$ is a subgroup of $G$, then something.
\end{exercise}

\begin{exercise}\label{A}
  If $H$ is a subgroup of $G$, then something.
\end{exercise}

\end{document}

Tags:

Spacing

Labels