5

In a mathematical text which I write, I want to denote a certain number by $S(x;q,a)$. The number, as you may have guessed, depends on three parameters $x, q, a$. I would like to give this expression a shortcut, because maybe I will change my mind in the end and rather denote the number as $S(x;a,q)$ or something the like. Then I will not have to go all over the text and look for instances of this expression.

So I defined a new command in the preamble in the following way:

\newcommand{\Sc}[3]{S(#1; #2, #3)}

This works, i. e. if I now type \Sc{x}{q}{a}, then the desired output is displayed.
Most times when I use this command, the three parameters I give to the command will be x, q, and a in this order. Only sometimes other parameters will occur in the use of \Sc. So a shortercut seems possible.

Ideally, I would like to only type \Sc as a shortcut for \Sc{x}{q}{a}. But the use \Sc{a}{b}{c} has to remain valid so that I can pass other parameters to \Sc if needed.
In order to achieve this, I tried

\newcommand{\Sc}[3][x][q][a]{S(#1; #2, #3)}

But apparently, there is at most one optional argument permitted in \newcommand, as I learned. (If this is wrong, please correct me.)

Is there a way to have all three parameters of my new command optional and such that x, q, and a are the defaul values?

Edit: Apparently, I didn't make the point clear enough. What I would like to typeset are two things. One is $S(x;q,a)$ with these three parameters x, q, and a. The other is $S(_; _, _)$ where I do not know yet what the three parameters are. Both should be possible with the same command \Sc.
For displaying $S(x;q,a)$, I would like to type only \Sc. So, in a sense, the parameters x (as the first parameter), q (second), and a (third) should be default. For displaying $S(_; _, _)$ with a parameter-triple (_, _, _) different from (x,q,a), I would like to use the command with all three parameters. For example I would type $\Sc{x}{q}{b}$ in order to produce $S(x;q,b)$.

5
  • Welcome to TSE! Commented Sep 3, 2021 at 9:50
  • 1
    Sorry, don't get your point, may be. With your first definition "\Sc{a}{y}{4}" will create "S(a;y;4)". Are you asking for "\Sc{a}{y}" creating "S(a;y;default-value)"? // If so, may be a few examples could better illustrate your point. // Thanks for clarifying
    – MS-SPO
    Commented Sep 3, 2021 at 9:52
  • 1
    @MS-SPO Thank you for commenting on this. In direct response: I am not asking for "\Sc{a}{y}" creating "S(a;y,default-value). Instead, I need all three parameters to have a default-value. I hope that my edit clarifies your question. If not, I will try to reformulate it.
    – NerdOnTour
    Commented Sep 3, 2021 at 10:03
  • 1
    you can define commands with three optional arguments with \NewDocumentCommand from xparse. But think carefully first if this is a good idea, and what the command should do if you give only one or two optional arguments. Commented Sep 3, 2021 at 10:16
  • 1
    This is not answering what you actually want, but you should know that \Sc xqa does the same thing as \Sc{x}{q}{a}, and if typing out those arguments is easy enough, maybe you don't need the default values. Commented Sep 3, 2021 at 20:51

4 Answers 4

12

I see two ways to do it.

With xparse you can use \NewDocumentCommand to create a new command with multiple optional arguments. Once you get beyond two optional arguments the usage becomes a bit clumsy and a key-value interface may be the better solution. The clumsiness is because with three consecutive optional arguments, if you only want to specify the third you must also specify the first and second. If you only want to specify the second you must also specify the first. Otherwise, there is no way to know which of the three optional arguments you are specifying.

MWE using xparse:

\documentclass{article}
\usepackage{xparse} % Automatically included in recent LaTeX releases;
                    % load manually as here for older releases.

\NewDocumentCommand{\Sc}{ O{x} O{q} O{a} }{%
  S(#1; #2, #3)
}%

\begin{document}
\Sc

\Sc[w][y][z] % change all three arguments

\Sc[m]       % change only the first argument

\Sc[x][m]    % change only the second argument

\Sc[x][q][m] % change only the third argument
\end{document}

Another way to do it is to use the xargs package, which provides the \newcommandx macro which, in turn, also lets you specify optional arguments with default values but the syntax and usage is a bit different. You don't explicitly have to supply the default value for, say, the first two arguments if all you want to change is the third argument, but you still must specify empty placeholder delimiters for the missing arguments.

MWE using xargs:

\documentclass{article}
\usepackage{xargs}

\newcommandx*{\Sc}[3][1=x,2=q,3=a,usedefault]{%
  S(#1; #2, #3)
}%

\begin{document}
\Sc

\Sc[w][y][z] % change all three arguments

\Sc[m]       % change only the first argument

\Sc[][m]     % change only the second argument

\Sc[][][m]   % change only the third argument
\end{document}

There may be other more elegant solutions. With three consecutive optional arguments, you need to be careful about what may happen if the user omits any of the arguments.

4
  • 1
    Thank you, this solves my problem. The fact that I have to type all three arguments if I only want to change the first is not a problem in my case, since this will happen rarely.
    – NerdOnTour
    Commented Sep 3, 2021 at 11:47
  • 1
    note that you dont need the xparse package with recent latex releases Commented Sep 3, 2021 at 13:09
  • Glad to have helped. I edited the first MWE's code to reflect @DavidCarlisle's comment. Commented Sep 3, 2021 at 15:16
  • 3
    With xparse, there are sneaky ways to deal with multiple consecutive optional arguments, which I wrote about at preppylion.com/weird-xparse-tricks The short version is instead of writing O{x} O{q} Q{a} in the arg spec you write O(x) s O{q} s O{sa} The normal use looks identical to the user, but if you want to specify only the second optional argument, you can write \Sc*[whatever] or to do the first and third, \Sc[first]**[third] I think that any time you're tempted to do three optional arguments like this, though, that you're better off using a key-val interface instead.
    – Don Hosek
    Commented Sep 3, 2021 at 15:18
4

I don't like the idea of specifying consecutive optional arguments without mandatory arguments between them:

If you wish to specify one of these optional arguments, you additionally need to specify at least all those optional arguments that are somewhere to the left of this optional argument.

I suggest doing things with one optional argument wherein you nest a triple of mandatory arguments:

(If you change your mind, all you need to do is change the way in which \InnerSc places its arguments.)

\documentclass{article}
\newcommand{\InnerSc}[3]{S(#1; #2, #3)}
\newcommand\Sc[1][{{x}{q}{a}}]{\InnerSc#1}

\begin{document}
\[ \Sc = \Sc[{a}{b}{c}] \]
\end{document}

enter image description here

If you like overkill you can use xparse/expl3 for creating a command \Sc with an optional argument where via key=value-interface you can specify only those things that shall deviate from the defaults:

\documentclass{article}

\RequirePackage{xparse}
\ExplSyntaxOn
% key=value-interface by means of package l3keys:
%-------------------------------------------------------
% Macros holding default-values of keys
%   \cs_new:Nn in order to get an error-message at this place
%   in case one of the macros  \__MYMODULE_Paramater_X: , 
%   \__MYMODULE_Paramater_Q: , \__MYMODULE_Paramater_A:
%   is already defined.
%   While carrying out an instance of \Sc these macros are
%   used as scratch-macros holding the values of the keys
%   ParameterX, ParameterQ and ParameterA.
\cs_new:Nn \__MYMODULE_Paramater_X: {x}
\cs_new:Nn \__MYMODULE_Paramater_Q: {q}
\cs_new:Nn \__MYMODULE_Paramater_A: {a}
\keys_define:nn { MYMODULE } {
  ParameterX.cs_set:Np = \__MYMODULE_Paramater_X: {},
  ParameterX.default:n = x,
  ParameterQ.cs_set:Np = \__MYMODULE_Paramater_Q: {},
  ParameterQ.default:n = q,
  ParameterA.cs_set:Np = \__MYMODULE_Paramater_A: {},
  ParameterA.default:n = a,
}
\NewDocumentCommand\Sc{O{}}{
  \group_begin:
  \keys_set:nn{ MYMODULE }{#1}
   S(\__MYMODULE_Paramater_X:;~\__MYMODULE_Paramater_Q:,~\__MYMODULE_Paramater_A:)
  \group_end:
}
\ExplSyntaxOff

\begin{document}
\[ \Sc = \Sc[ParameterX=a, ParameterQ=b, ParameterA=c] \]

\[ \Sc = \Sc[ParameterX=a, ParameterA=c, ParameterQ=b] \]

\[ \Sc = \Sc[ParameterX=a, ParameterA=c] \]

\[ \Sc = \Sc[ParameterQ=w] \]

\[ \Sc = \Sc[ParameterQ, ParameterX, ParameterA] \]
\end{document}

enter image description here

In this code-example, the keys have long names like ParameterX and ParameterQ and ParameterA. Therefore, when sticking to these names, you have to type a lot.

I chose these long names to make it easier to understand everything when you look at the code example.

Of course in a real-life-scenario I would give the keys names that are not that long.

I might name them just X/Q/A or the like.

Or I might give them semantic names. I could not do that in this example because in your question you only revealed that expressions of pattern S(#1; #2, #3) denote (whatsoever) numbers, but you did not reveal whether for the components #1 respective #2 respective #3 of that pattern there are specialized terms that are tailored to the context of such expressions.
(E.g. expressions of the pattern \frac{#1}{#2} denote fractions. The component #1 of that pattern denotes the numerator. The component #2 of that pattern denotes the denominator. "numerator" and "denominator" are specialized terms tailored to the context of fractions. So in a key=value-interface for typesetting fractions, the keys could be named "numerator" respective "denominator".)

4
  • I don’t really see the point of the ~’s.
    – Gaussler
    Commented Sep 5, 2021 at 14:57
  • @Gaussler With \ExplSyntaxOn space is an ignored character and ~ has catcode 10, i.e., has the rôle which without \ExplSyntax the space character has. It is not really needed in math mode but the example of the questioner has spaces, and I don't know if whatsoever usage outside math-mode is intended as well. Commented Sep 5, 2021 at 16:47
  • I know how space and ~ work in expl3, which was precisely why I did not see the point of having these ~’s which would be ignored in math mode anyway. I did not consider the text mode option, though.
    – Gaussler
    Commented Sep 5, 2021 at 17:04
  • @Gaussler I don't take the text mode option for likely but I tend to change as few of the things provided by the questions as possible. As ~ are superfluous but not really a nuisance in math-mode... Commented Sep 5, 2021 at 17:09
3

The syntax \Sc[y;r,b] seems quite practical and semantic, but you can later change the output in any way you like.

\documentclass{article}
\usepackage{amsmath}

\NewDocumentCommand{\Sc}{>{\SplitArgument{1}{;}}O{x;q,a}}{\ScAux#1}
\NewDocumentCommand{\ScAux}{m >{\SplitArgument{1}{,}}m}{S(#1;\ScAuxA#2)}
\NewDocumentCommand{\ScAuxA}{mm}{#1,#2}

\begin{document}

$\Sc$

$\Sc[y;r,b]$

\end{document}

The trick is that with \SplitArgument{1}{;} the argument will be split into two pairs of braced groups. So the call with no optional argument will in turn do

\ScAux{x}{q,a}
S(x;\ScAuxA{q}{a})
S(x;q,a)

as desired. The 1 refers to the number of expected delimiters, for the first call a semicolon, for the second a comma.

The same if we call \Sc[y;r,b] to get

\ScAux{y}{r,b}
S(x;\ScAuxA{r}{b})
S(x;r,b)

enter image description here

1

A keyval solution similar to the one by @UlrichDiez, but using the package semantex (disclaimer: I am the author).

\documentclass{article}

\usepackage{semantex}

\NewSymbolClass{\MySymbolClass}

\NewObject{\MySymbolClass}{\Sc}{S}[
    data provide=data x,
    data provide=data q,
    data provide=data a,
    define keys[1]={
        {x}{ data set={data x}{#1} },
        {q}{ data set={data q}{#1} },
        {a}{ data set={data a}{#1} },
    },
    x={x},
    q={q},
    a={a},
    parse options={
        set arg keys x={
            sep={\SemantexDataGetExpNot{data x}},
            other sep={;}{\SemantexDataGetExpNot{data q}},
            sep={\SemantexDataGetExpNot{data a}},
        },
    },
]

\begin{document}

\( \Sc = \Sc[x=x,q=q,a=a] \neq \Sc[x=7,q=14,a=23] \)

\end{document}

enter image description here

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .