How to patch a floating environment so that the patched command floats

I'm using etoolbox to patch some environments. I want to use \AtBeginEnvironment{table}{\marginpar{foo}} to put something in the margin by the float. But the marginpar is typeset where the environment is written, not where the float is output, if you see what I mean. How can I get something to float with the table?

-

Based on Martin Scharrer's redefinition of the table environment and egreg's statement that insertions are forbidden inside insertions: This is a case where \marginpar doesn't work, but \marginnote (from the marginnote package) does.

\documentclass{article}

\usepackage[english]{babel}
\usepackage{blindtext}

\usepackage{marginnote}

\makeatletter
\renewenvironment{table}[1][]{\@float{table}[#1]\marginnote{foo}}{\end@float}
\makeatother

\begin{document}

\blindtext

\begin{table}
\centering
(Table content)
\caption{A table}
\end{table}

\end{document}

-
Nice. Much better than my hack: \llap{\raisebox{-\height}[0pt][0pt]{\parbox{\marginparwidth}{foo\\bar}}\hspace{\‌​marginparsep}}% \vspace{-1ex} –  Martin Scharrer Jul 17 '11 at 22:21
I guess this sort of redefinition might break if you load booktabs or similar? (Or does that only mess with tabular...) –  Seamus Jul 18 '11 at 9:56
It's probably easier for my purposes to patch caption rather than the float. But thanks for the marginnote tip¬ –  Seamus Jul 18 '11 at 15:28

You can't. Both tables and marginpars are insertions and it's forbidden to have an insertion inside an insertion.

If you try to put a \marginpar in a table environment you get

! LaTeX Error: Float(s) lost.


Martin's redefinition doesn't work either:

! LaTeX Error: Not in outer par mode.


It wouldn't work anyway.

-
Yeah, yeah, always test your own code ... This reminds me on the footnote inside a footnote question which ironically got answered by Seamus. You could try to fake the marginpar by using \rlap{\hspace{<large enough>}foo} or similar. –  Martin Scharrer Jul 17 '11 at 22:00
OK. So you can't put a marginpar in a table. But can you (in general) get something to float with a float by patching some command? –  Seamus Jul 18 '11 at 13:07
@Seamus No, it's forbidden by TeX rules. TeXbook, p. 117 –  egreg Jul 18 '11 at 13:14
@egreg: couldn't you define the figure environment as something like \savebox\FloatBox\vbox\bgroup and \egroup\TurnFloatBoxIntoAnInsertion, allowing nested floating objects? –  Bruno Le Floch Dec 13 '11 at 17:13
@BrunoLeFloch When then \FloatBox goes inside the \insert, the \insert inside it will become illegal. Only if you manage floats without \insert this becomes possible. –  egreg Dec 13 '11 at 17:39

The AtBeginEnvironment code is executed just before the internal macro of the environment (\table) here:

\$ latexdef -p etoolbox begin

\begin:
macro:#1->\csuse {@beforebegin@#1@hook}%
\@ifundefined {#1}%
{\def \reserved@a {\@latex@error {Environment #1 undefined}\@eha }}%
{\def \reserved@a {\def \@currenvir {#1}\edef \@currenvline {\on@line }
\csuse {@begin@#1@hook}\csname #1\endcsname }}%
\@ignorefalse \begingroup \@endpefalse \reserved@a


The important part here is \csuse {@begin@#1@hook}\csname #1\endcsname. So you can't use these hooks to do this.

Note that table is simply:

\table:
\long macro:->\@float {table}

\endtable:
\long macro:->\end@float


So I would write:

\renewenvironment{table}[1][]{\@float{table}[#1]\marginpar{foo}}{\end@float}


and insert the code manually. Of course you need to be careful if you load any packages which change the definition of table.

-