2

Popular ways to define a macro with optional arguments is using TeX's \def with the aid of \@ifnextchar[ and/or LaTeX's \newcommand. In both cases, macro's definition usually contains its optional arguments.

Now, I want to use optional arguments just as a sort of junction which decides how macro expands. The option itself is not used in macro's definition explicitly.

For a simple instance, let me define \conjTrans, which denotes a conjugate transpose of a matrix in three notations. The specification of \conjTrans is as follows:

\documentclass{standalone}
\usepackage{conjTrans} % \conjTrans is defined here
\begin{document}
$\conjTrans{A}$,
$\conjTrans[asterisk]{B}$,
$\conjTrans[Hermite]{C}$, and
$\conjTrans[dagger]{D}$
\end{document}

will produce

output image,

and if invalid option (e.g. dager) is given, an error like the option is incorrect occurs.

I first tried to utilize \ifx or other conditional branches, but it didn't go well with my competence because options are more than one token and I don't know the solution to it.

I implemented \conjTrans with the following code.

% conjTrans.sty
\ProvidesPackage{conjTrans}[2016/01/05 my first question on TeX.SX]
\RequirePackage{amsmath}
\def\conjTrans{\@ifnextchar[\nkt@conjTrans{\nkt@conjTrans[asterisk]}}
\def\nkt@conjTrans[#1]#2{%
    \expandafter\ifx\csname nkt@conjTrans@#1\endcsname\relax
        \PackageError{conjTrans}{The option #1 is unknown to \string\conjTrans}{Optional argument for \string\conjTrans\space must be either ast, H, or dagger.}%
    \else
        \csname nkt@conjTrans@#1\endcsname#2%
    \fi
}
\def\nkt@conjTrans@asterisk#1{\boldsymbol#1^{\ast}}
\def\nkt@conjTrans@Hermite#1{\boldsymbol#1^{\text{H}}}
\def\nkt@conjTrans@dagger#1{\boldsymbol#1^{\dagger}}

This \conjTrans seems to work quite well, but I wonder if there is a method which is more sophisticated, safer, or better in certain sense than mine. Are there any standard “idioms” to use optional arguments in this way?

  • I don't know what you are after? Do you want to hide the optional argument in moving arguments? – user31729 Jan 5 '16 at 14:40
  • This is essentially a duplicate of Peter's question from the other day tex.stackexchange.com/questions/285822/… (or at least the same answers apply) your csname suggestion being my answer there, more or less – David Carlisle Jan 5 '16 at 14:41
  • @ChristianHupfer I'm afraid I don't get what you mean by "in moving arguments". – yudai-nkt Jan 5 '16 at 14:51
  • @DavidCarlisle Sorry, I thought I checked whether there is a duplicate before posting, but could not find the question. Seems like answers there is helpful though I don't peruse them yet. – yudai-nkt Jan 5 '16 at 14:56
4

In this case I think a key-value approach is the best one:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\conjTrans}{O{asterisk}m}
 {
  \yudai_conj_trans:nn { #1 } { #2 }
 }

\keys_define:nn { yudai/conjtrans }
 {
  asterisk .code:n = \tl_set:Nn \l_yudai_conj_trans_symbol { * },
  Hermite  .code:n = \tl_set:Nn \l_yudai_conj_trans_symbol { \mathrm{H} },
  dagger   .code:n = \tl_set:Nn \l_yudai_conj_trans_symbol { \dagger },
  asterisk .value_forbidden:n = true,
  Hermite  .value_forbidden:n = true,
  dagger   .value_forbidden:n = true,

  unknown  .code:n = \msg_error:nnx { yudai/conjtrans } { bad-option } { \l_keys_key_tl }
                     \tl_set:Nn \l_yudai_conj_trans_symbol { ??? },
 }

\msg_new:nnnn { yudai/conjtrans } { bad-option }
 {
  Bad~option~#1
 }
 {
  You~used~#1,~which~is~not~among~the~predefined~options
 }

\tl_new:N \l_yudai_conj_trans_symbol

\cs_new_protected:Nn \yudai_conj_trans:nn
 {
  \keys_set:nn { yudai/conjtrans } { #1 }
  #2^{\l_yudai_conj_trans_symbol}
 }
\ExplSyntaxOff

\begin{document}

$\conjTrans{A}$,
$\conjTrans[asterisk]{B}$,
$\conjTrans[Hermite]{C}$,
and $\conjTrans[dagger]{D}$

Error: $\conjTrans[foo]{E}$

\end{document}

This is easily extendable.

enter image description here

A “classical” implementation:

\documentclass{article}

\newcommand{\conjTrans}[2][asterisk]{#2\conjTransAppend{#1}}

\newcommand{\conjTransAppend}[1]{%
  \ifcsname conjTrans#1\endcsname
    ^{\csname conjTrans#1\endcsname}
  \else
    \PackageError{conjTrans}{Invalid option #1}
      {The option #1 is not among the predefined ones}%
    ^{???}%
  \fi
}
\newcommand{\conjTransasterisk}{*}
\newcommand{\conjTransHermite}{\mathrm{H}}
\newcommand{\conjTransdagger}{\dagger}

\begin{document}

$\conjTrans{A}$,
$\conjTrans[asterisk]{B}$,
$\conjTrans[Hermite]{C}$,
and $\conjTrans[dagger]{D}$

Error: $\conjTrans[foo]{E}$

\end{document}
  • Your second implementation and mine are similar to me at least, and I'd like to know the advantage of using \conjTransAppend if it exists. I'm unfamiliar with the expl3 syntax, so maybe I have to study. – yudai-nkt Jan 5 '16 at 15:52
  • @yudai-nkt Using \conjTransAppend is just not to clobber the main definition: divide et impera – egreg Jan 5 '16 at 15:54
  • I'm afraid I cannot understand a possibility of overwriting the main definition. – yudai-nkt Jan 5 '16 at 16:08
  • @yudai-nkt I believe it's better to be “modular”. – egreg Jan 5 '16 at 16:09
0
\documentclass[a4paper]{article}
\usepackage{filecontents}
\begin{filecontents*}{conjTrans.sty}
\ProvidesPackage{conjTrans}[2016/01/05 my first question on TeX.SX]
\RequirePackage{amsmath}
\RequirePackage{xkeyval}
\define@choicekey*+{conjTrans}{symbol}[\val\nr]{,asterisk,Hermite,dagger}%
  {\ensuremath{\ifcase\nr\relax
    \cTB@se^*\or\cTB@se^\text{H}\or\cTB@se^{\dagger}\fi}}
  {\PackageWarning{conjTrans}{erroneous input ignored}}
\newcommand\conjTrans[2][asterisk]{\def\cTB@se{\boldsymbol{#2}}\setkeys{conjTrans}{symbol=#1}}
\endinput
\end{filecontents*}

\usepackage{conjTrans}
\begin{document}
\conjTrans{A}, \conjTrans[asterisk]{B}, \conjTrans[Hermite]{C}, and 
\conjTrans[dagger]{D} 

\conjTrans[whatever]{A}%% For an error message in the log file
\end{document} 

enter image description here

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.