# Environment with key-value options using expl3

I am new to expl3 and would like to create an environment with various key-value arguments. At the moment I am struggling to detect weather a key was set or not.

\documentclass{article}
\usepackage{xparse,graphicx}

\ExplSyntaxOn
% keys
\keys_define:nn { mybodule/bfigure }
{
caption .tl_set:N = \l_mybodule_caption,
shift .dim_set:N  = \l_mybodule_shift  ,
shift .default:n  = 0em
}

\NewDocumentEnvironment{bfigure}{O{}}{
\keys_set:nn { mybodule/bfigure } { #1 }
\tl_if_empty:NTF \l_mybodule_caption {true} {false}
}{}
\ExplSyntaxOff

\begin{document}
\begin{bfigure}[caption=mycaption]
\includegraphics[width=3cm]{example-grid-100x100pt}
\end{bfigure}
\end{document}


What it the correct way to implement the if caption set then ... else ... part? Am I even using the \keys_define and \keys_set:nn correctly?

• Off topic: I'm wondering if you want shift .default:n = 0em or shift .initial:n = 0em. The .default value is used when you give the key without value ([shift]), the .initial value is the pre-set value that is used if the key is not used. Jul 19 '20 at 7:00
• Your \tl_if_empty:NTF appears to work. Since a newly define tl variable is always empty your code should also be safe. But you should probably wait for a real expl3 expert for confirmation. If you want to be on the safe side you can add caption .initial:n = {},, but if I'm right this is not needed as long as you keep your \keys_set:nn { mybodule/bfigure } { #1 } calls local and don't re-use \l_mybodule_caption anywhere. Jul 19 '20 at 7:04
• FWIW the answer to tex.stackexchange.com/q/417064/35864 uses several .tl_set:Ns and checks for their presence with \tl_if_empty:NTF/\tl_if_empty:NF. Look for \l_guide_number_tl and \l_guide_keywords_tl. Jul 19 '20 at 7:06
• \l_mybodule_caption should probably be called \l_mybodule_caption_tl and \l_mybodule_shift would be \l_mybodule_shift_dim if you want to follow expl3 naming conventions. Jul 19 '20 at 7:09

Since you're using the keys inside an environment, you need not worry about their initial values in a different environment, because the assigned values will be forgotten as soon as the environment ends.

For instance

\documentclass{article}
\usepackage{xparse,graphicx}

\ExplSyntaxOn
% keys
\keys_define:nn { mybodule/bfigure }
{
caption .tl_set:N = \l_mybodule_caption_tl,
shift .dim_set:N  = \l_mybodule_shift_dim,
}

\NewDocumentEnvironment{bfigure}{O{}}
{
\keys_set:nn { mybodule/bfigure } { #1 }
\tl_if_empty:NTF \l_mybodule_caption_tl {true} {false}
}
{}
\ExplSyntaxOff

\begin{document}

\begin{bfigure}
\includegraphics[width=1cm]{example-grid-100x100pt}
\end{bfigure}

\begin{bfigure}[caption=mycaption]
\includegraphics[width=1cm]{example-grid-100x100pt}
\end{bfigure}

\begin{bfigure}
\includegraphics[width=1cm]{example-grid-100x100pt}
\end{bfigure}

\end{document}


will produce

Please, use the proper naming conventions, ending each variable's name with the variable type.

Note that .default is not the initial value given to the key, but the value assigned if no = symbol follows the key. If you want to assign an initial value to a key, to be used when the key is not supplied, use

shift .initial = 12pt,


or whatever value. Stating 0pt as initial value is not necessary, because dim variables are initialized to be zero, just like tl variables are initialized to empty.

If you want to print the caption if the key has been set, do

\tl_if_empty:NF \l_mybodule_caption_tl
{
\caption{\l_mybodule_caption_tl}
}


at the appropriate spot.