# Expansion of an optional parameter for an environment

I want to define a custom environment, which takes an optional parameter, and I want be able to link to the environment using nameref. To this end, I tried something similar to the following MWE:

\documentclass{article}

\usepackage{hyperref}
\usepackage{caption}
\usepackage{trace}

\newenvironment{myenv}[1][]
{
% define auxiliary variable, as #1 is not allowed in the end part of a newenvironment
\def\myarg{#1}
}
{
\captionof{table}{\myarg}
}

\begin{document}
\begin{myenv}[A title.\label{myenv:title}]
Something that pretends to be a table.
\end{myenv}

\traceon
\nameref{myenv:title}
\traceoff

\end{document}


Tracing shows hyperref is defining the following macro:

\r@myenv:title ->{1}{1}{\myarg \relax }{table.1}{}


which, predictably, gives me an

! Undefined control sequence.
<argument> \myarg


I guess that makes sense, as \myarg is only defined in the scope of the environment. My question is now: How do I force \myarg to expand before it is passed to \r@myenv:title?

I have already taken a look at a similar question about expansion, but was not able to adapt that solution.

If you're using xparse's \NewDocumentEnvironment you can use the arguments in the end part directly. In the code below I used \IfValueT to check whether the optional argument was given at all and only then use the \caption. If you don't do this check you're setting an empty caption each time you omit the optional argument. Another option would be to use a mandatory argument in the first place, as you're directly forwarding it to \caption (this would be done with \NewDocumentEnvironment{myenv}{ m } instead of o).

Unrelated note: hyperref should be loaded as the last package in your document (there are a few exceptions to this rule of thumb, e.g. cleveref should be loaded after it).

\documentclass{article}

\usepackage{caption}
\usepackage{trace}
\usepackage{xparse}

\NewDocumentEnvironment{myenv}{ o }
{}
{%
\IfValueT{#1}{\captionof{table}{#1}}%
}

\usepackage{hyperref}

\begin{document}
\begin{myenv}[A title.\label{myenv:title}]
Something that pretends to be a table.
\end{myenv}

\traceon
\nameref{myenv:title}
\traceoff

\end{document}

• Yes, I am actually sending the argument through \ifdefstring first, just left it out for the sake of the MWE. – LokiRagnarok Jun 24 '19 at 13:36
• @KonstantinKotenko you should also make sure to put a % after an opening brace, that would otherwise include a space in your code. – Skillmon Jun 24 '19 at 13:39

The key is to expand \myarg in the closing part of your environment definition.

\documentclass{article}

\usepackage{hyperref}
\usepackage{caption}
\usepackage{trace}

\newenvironment{myenv}[1][]
{
% define auxiliary variable, as #1 is not allowed in the end part of a newenvironment
\def\myarg{#1}
}
{
\def\tmp{\captionof{table}}%
\expandafter\tmp\expandafter{\myarg}
}

\begin{document}
\begin{myenv}[A title.\label{myenv:title}]
Something that pretends to be a table.
\end{myenv}

\traceon
\nameref{myenv:title}
\traceoff

\end{document}