3

The BioMed Central LaTeX class, bmcart.cls, redefines \end in a manner that causes downstream errors when used in conjunction with breqn.sty.

The offending portion of bmcart.cls is provided below:

\def\end#1{%
  \@ifundefined{pseudo@#1}%
    {\org@end{#1}}{\csname pseudo@#1\endcsname[1]\relax}%
}

This modified definition of \end is used by the class to permit the function of a new syntax element, \newpseudoenvironment, which appears to be used by the publisher to define global definitions in a more convenient fashion.

Unfortunately, breqn also redefines \end, in an incompatible manner. When breqn is loaded after the bmcart class, the following error occurs:

Runaway argument?
\@ifundefined {pseudo@##1}{\org@end {##1}}{\csname pseudo@##1\endcsname \ETC.
/usr/share/texlive/texmf-dist/tex/latex/breqn/breqn.sty:848: Paragraph ended be
fore \@tempa was complete.
<to be read again> 
                   \par 
l.848   \par

If the above lines of bmcart.cls are commented out, this error does not occur.

With the help of LianTze Lim and Graham Douglas, I am now storing the LaTeX default definition of \end and then restoring it after loading bmcart.cls, also storing its definition. This current patch is provided as an answer to this question.

While this solution allows my project to compile, it does not completely fix the underlying issue, in that it does not allow \newpseudoenvironment to function (see lines 302–320 of bmcart.cls for its definition and its associated re-definitions of \start and \end), as intended (which may be needed by the publisher). More generally, it would be nice to find a solution that allows breqn to use its definition of \end, while allowing all other packages to use the applicable default or class-specific definition.

We provide below the definitions of various \end commands, kindly compiled by Graham Douglas:

\latexend:
\csname end#1\endcsname \@checkend {#1}\expandafter \endgroup
\if@endpe \@doendpe \fi \if@ignore \@ignorefalse \ignorespaces \fi

\brqend:
\csname end#1\endcsname \latex@end {#1}

\latex@end:
\@checkend {#1}\expandafter \endgroup \if@endpe \@doendpe
\fi \if@ignore \@ignorefalse \ignorespaces \fi

\org@end:
\csname end#1\endcsname \@checkend {#1}\expandafter \endgroup
\if@endpe \@doendpe \fi \if@ignore \@ignorefalse \ignorespaces \fi

\bmcend:
\@ifundefined {pseudo@#1}{\org@end {#1}}{\csname pseudo@#1\endcsname
[1]\relax }

Can anyone suggest an improved solution, which accomplishes one of the following things (or suggests some better alternative)?

  1. Encapsulates the breqn definition of \end such that it does not cause compatibility issues, but is still used for all breqn environments.
  2. Encapsulates the bmcart.cls definition of \endsuch that it does not cause compatibility issues, but allows its pertinent case of pseudo@#1 to be defined automatically and used only by \newpseudoenvironment.
  3. Restores the bmcart.cls definition of \end after loading breqn.sty, but still manages to permit breqn environments, like dmath, to function correctly.
1
+100

The trick is that both packages work fine, if the breqn \end is used inside the bmcart \end, so breqn would have to be loaded first. This would be weird and could lead to other errors, so we swap the definitions around:

\documentclass{bmcart}

\makeatletter
\let\bmcend\end % save \bmcend
\let\end\org@end % breqn has to see the original \end
\usepackage{breqn}
\let\org@end\end % let bmcart believe the breqn \end is the original
\let\end\bmcend % and give control back to bmcart
\makeatother

% Some demonstration
\newpseudoenvironment{pseudo}{}{}
\newenvironment{real}{}{}
\begin{document}
\begin{dmath}
abc=def=ghi=jkl
\end{dmath}

\begin{real}
  \the\currentgrouplevel
\end{real}

\begin{pseudo}
  \the\currentgrouplevel
\end{pseudo}
\end{document}

I added some environments to show that everything works. Especially there is no group created by the pseudoenvironmnt: enter image description here

Instead of splitting this fix with commands before and after loading the package, you can use the scrlfile package to insert the commands in the right places:

\documentclass{bmcart}
\usepackage{scrlfile}
\makeatletter
\BeforePackage{breqn}{
  \let\bmcend\end % save \bmcend
  \let\end\org@end % breqn has to see the original \end
}
\AfterPackage{breqn}{
  \let\org@end\end % let bmcart believe the breqn \end is the original
  \let\end\bmcend % and give control back to bmcart
}
\makeatletter
\usepackage{breqn}

This is especially useful if breqn is loaded by another package and it even works if it is not loaded at all.

Alternatively the bmcart pseudoenvironments can be integrated into the breqn system: A pseudoenvironment only has to define a \end... command which gobbles two arguments:

\documentclass{bmcart}
\makeatletter
\let\end\org@end
\def\newpseudoenvironment#1#2#3{%
  \global\@namedef{end#1}##1##2{#3}%
  \global\@namedef{pseudo@#1}[##1]{%
    \relax#2%
  }%
}
\makeatletter
\usepackage{breqn}

I think the second approach looks cleaner, but it might break in some edge cases:

A pseudo environment has two fundamental differences to a normal environment:

  1. It does not introduce a group. This means that definitions inside of a pseudoenvironment might leak out of the environment. Let for example pseudo and real be the pseudo environment from the code snippet above than

    \begin{real}
      \scshape This is in small caps.
    \end{real}
    Here we have a normal font again.
    \begin{pseudo}
      \scshape This is in small caps again
    \end{pseudo}
    Oops, still small caps.
    

    This is useful for example for environemnts similiar to the LaTeX lrbox environment. It saves its content in a savebox passed as parameter. For the assignment of the savebox to be visible outside of the environment the grouping has to be avoided. This could be done with a pseudo environment. lrbox itself has to use some tricks instead.

    This is probably the intended use-case for pseudo-environments.

  2. There is another difference through. If you ever tried to make an environment named e.g. def (for example for definitions), you are aware that there can not be a LaTeX environment with the same name as a LaTeX macro, because an environment named e.g. foo is defined by the macros \foo and \endfoo. This naming conflict is resolved for pseudo environments, so

    \newpseudoenvironment{def}{Definition: }{. End of Definition}
    % or even
    \newcommand\something{I'm a macro.}
    \newpseudoenvironment{something}{I'm an environment.}{The end.}
    

    are valid. This can be useful if the same functionality has to be provided as a command and as an environment. An example where some tricks are used have a similar effect with normal environment is beamers \frame and {frame}.

  3. This also works for \end.... So you could define

    \newcommand\endsomething{...}
    \newpseudoenvironment{something}{...}{...}
    

    This case, a independent \end... macro, would work with bmcart and with the first fix, but not with the second. But I do not know of any reason why someone would do this, so this normally should not be a problem. Also LaTeX will not allow to define any command starting with \end... via \newcommand anyway, so this would require using the \def primitive.

This should not be a problem with the first approach.

1

N.B. This answer does not satisfactorily solve the above-posed question in a general manner. Additional ideas would be very much appreciated.


The current patch, mentioned above, is provided below:

% before loading bmcart.cls
\RequirePackage{letltxmacro}

\GlobalLetLtxMacro{\LaTeXend}{\end}

% ... 

% after loading the class

\LetLtxMacro{\bmcend}{\end}
\LetLtxMacro{\end}{\LaTeXend}

% ...

\usepackage{breqn}

Thanks to LianTze Lim and Graham Douglas for a similar solution, from which this was adapted.

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.