0

While writing a few macros to wrap around float environments, I stumbled upon failure of macro-expansion (at least I think so) when it comes to storing float specifiers.

main.tex:

\documentclass{scrartcl}
\usepackage{fontspec}
\usepackage{myfig}

\begin{document}
\section{Dummy section}

%\begin{myfig}[b!]
\begin{myfig}
  Yadda yadda yadda
\end{myfig}

\end{document}

myfig.sty:

\ProvidesPackage{myfig}
\makeatletter
\newcommand{\@std@float@align}{p!}
%\newenvironment{myfig}[1][t!]{
\newenvironment{myfig}[1][\@std@float@align]{
  \begin{figure}[#1]
}{
  \end{figure}
}
\makeatother

When compiling with xetex, this gives me:

./main.tex:10: LaTeX Error: Unknown float option `\'.

I tried getting it to work with the strategy proposed in 3. of this answer, trying to understand tex expansion. Judging from me posting this question, I failed. How do I get to store my float specifier in a macro and use it?

tifrel
  • 302
  • 2
    Try \begingroup\edef\x{\endgroup\noexpand\begin{figure}[#1]}\x. If you have a recent enough (later than TeXLive 2019) XeTeX, then \expanded{\noexpand\begin{figure}[#1]} – Phelype Oleinik Mar 27 '20 at 19:32
  • Thanks a lot, that fixed it! Can you elaborate what caused the failure and how you fixed it? – tifrel Mar 27 '20 at 19:39
  • in addition to Phelype's comment you are missing % from ends of lines so your definitions have unwanted space tokens, but as I note in the answer below you do not need the redefinition at all here. – David Carlisle Mar 27 '20 at 19:44
  • 1
    @tillyboy The error happens because the optional argument of floating environments treat the argument as a string, so \foo is \ f o o, and not whatever \foo expands to. Using \edef (or \expanded) like that expands everything (except for \begin, which is prefixed with \noexpand) and then starts the figure with \@std@float@align expanded. Though David's suggestion of redefining \fps@figure is the proper way of doing this. – Phelype Oleinik Mar 27 '20 at 19:50

1 Answers1

3

You should never use ! routinely. ! means ignore the (user specified) constraints on float placement. So it is better to set constraints that you want rather than always ignoring the constraints.

The default figure placement is \fps@figure

So to make the default be b you just need

\makeatletter
\renewcommand\fps@figure{b}
\makeatother

There is no need to redefine the figure environment.

David Carlisle
  • 757,742
  • I use the ! for testing purposes, to get more robust results ;) Is there something like \fps@float that affects all floats (including newly defined ones)? – tifrel Mar 27 '20 at 20:06
  • 1
    @tillyboy even for testing using a default of "ignore the defaults" means you are testing the wrong thing. latex itself doesn't have a float definition command, but if you are using the float package you specify the default placement when defining the float as 2nd argument to \newfloat – David Carlisle Mar 28 '20 at 00:24