Recall arbitrary positional argument
You can build an internal command of the right form
\documentclass{article}
\def\switchtwo#1#2#3{%
\def\tmp##1##2{###3}%
\tmp{#1}{#2}}
\usepackage[T1]{fontenc}
\begin{document}
\switchtwo{aaa}{bbb}{1}
\switchtwo{\string\or}{\string\fi}{2}
\end{document}
\newcommand{\switchtwo}[3]{#(#3)}
— The syntax you have in mind implies the possibility of using #⟨whatsoever⟩
for "dynamically" denoting arguments of a macro at times when that macro is expanded.
This is not possible in (La)TeX:
Only at the time of defining a macro you can use #1
and #2
etc for denoting its parameters.
Denoting one of its arguments by #⟨whatsoever⟩
at the time of expanding is not possible.
At the time of expanding, the ⟨parameter-text⟩
of a macro's definition is taken for a set of directives for one by one gathering arguments from the token-stream:
When expansion of \switchto
takes place, LaTeX gathers the arguments from the token-stream: First it gathers from the token-stream that argument/that set of tokens that is denoted by the definition-text's parameter #1
. Then it gathers from the token-stream that argument/that set of tokens that is denoted by the definition-text's parameter #2
. Then it gathers from the token-stream that argument/that set of tokens that is denoted by the definition-text's parameter #3
. Then it inserts these sets of tokens into the replacement-text which it returns to the token-stream.
What can you do in LaTeX?
David Carlisle showed in his answer how to use ##⟨whatsoever⟩
within the definition-text of a macro for "dynamically denoting" one of the arguments of another macro, a temporary macro, at the time of defining that other/temporary macro.
Approaches focused at defining temporary macros cannot be used in expansion-contexts.
Other possibilities (that can be used in expansion-contexts as well) are:
As long as it is ensured that the third argument is a ⟨number⟩
in the sense of The TeXbook—the precise meaning of the quantity ⟨number⟩
is discussed in The TeXbook, Chapter 24: Summary of vertical mode —, you can probably do something like this:
\documentclass{article}
\makeatletter
\newcommand{\switchtwo}[3]{%
\romannumeral0\ifnum\number\number0#3=1 \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{\expandafter\@firstoftwo\@secondoftwo}{%
\ifnum\number\number0#3=2 \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
{\expandafter\@secondoftwo\@secondoftwo}%
{\@firstoftwo}%
}%
{ Error: Arg 3 is neither 1 nor 2}{{ #1}{ #2}}%
}%
\makeatother
\begin{document}
\switchtwo{A}{B}{1}
\switchtwo{A}{B}{2}
\switchtwo{A}{B}{3}
\switchtwo{A}{B}{}
\hrulefill
\newcounter{foobar}
\setcounter{foobar}{1}%
\switchtwo{A}{B}{\number\value{foobar}}
\setcounter{foobar}{2}%
\switchtwo{A}{B}{\number\value{foobar}}
\setcounter{foobar}{3}%
\switchtwo{A}{B}{\number\value{foobar}}
\end{document}
In the example above \romannumeral0...
is not used for obtaining the roman-numeral-representation of a number. \romannumeral0...
is used for triggering a lot of expansion-work during the search for more digits or a space-token that will be discarded as it just terminates the digit-sequence and therefore also terminates the search for more digits. It is ensured that after all this expansion-work a space-token is found, which terminates the digit-sequence 0
. Therefore after all the expansion-work a non-positive number is found while \romannumeral
will silently swallow non-positive numbers without returning any tokens at all.
Be aware that a reliable test whether an arbitrary token sequence in \switchtwo
's third argument forms a valid ⟨number⟩
in the sense of The TeXbook is not feasible:
An arbitrary token sequence might form an arbitrary expansion-based algorithm. Therefore such a test includes testing whether the result of an arbitrary expansion-based algorithm forms a valid ⟨number⟩
in the sense of The TeXbook. This in turn implies testing whether an arbitrary expansion-based algorithm terminates at all (without error-messages). This in turn implies solving the halting problem. Alan Mathison Turing proved in 1936 that a general algorithm to solve the halting problem for all possible program-input pairs does not exist.
In case you prefer checking whether the set of tokens contained in \switchto
's third argument (without whatsoever expansion/evaluation) consists either exactly of the catcode-12-(other)-character-token 1
or exactly of the catcode-12-(other)-character-token 2
or of something else, this can be done by means of delimited arguments:
\documentclass{article}
\makeatletter
%%-----------------------------------------------------------------------------
%% Check whether argument is empty:
%%.............................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is empty>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is not empty>}%
%%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
%% <https://groups.google.com/forum/#!original/comp.text.tex/kuOEIQIrElc/lUg37FmhA74J>
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral0\expandafter\@secondoftwo\string{\expandafter
\@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\@secondoftwo\string}\expandafter\@firstoftwo\expandafter{\expandafter
\@secondoftwo\string}\@firstoftwo\expandafter{} \@secondoftwo}%
{\@firstoftwo\expandafter{} \@firstoftwo}%
}%
%%-----------------------------------------------------------------------------
%% \UD@DigitFork{<Argument which is to be checked>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is formed by a set of
%% tokens which contains only the catcode-12-character 1>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is formed by a set of
%% tokens which contains only the catcode-12-character 2>}%
%% {<Tokens to be delivered in case that argument
%% which is to be checked is formed by a set of
%% tokens which is empty or contains something else>}%
%%
\@ifdefinable\UD@GobbleToExclam{\long\def\UD@GobbleToExclam#1!{}}%
\@ifdefinable\UD@DigitSelect{\long\def\UD@DigitSelect#1!!1!2!#2#3!!!!{#2}}%
\newcommand\UD@DigitFork[4]{%
\expandafter\UD@CheckWhetherNull\expandafter{\UD@GobbleToExclam#1!}{%
\UD@DigitSelect
!#1!1!2!{#4}% empty
!!#1!2!{#2}% 1
!!1!#1!{#3}% 2
!!1!2!{#4}% something else without !
!!!!%
}{#4}% something else with !
}%
%%-----------------------------------------------------------------------------
%% \switchto
\newcommand\switchtwo[3]{%
\romannumeral0\UD@DigitFork{#3}{ #1}{ #2}{ Error: Arg 3 is neither 1 nor 2}%
}%
\makeatother
\begin{document}
\switchtwo{A}{B}{1}
\switchtwo{A}{B}{2}
\switchtwo{A}{B}{3}
\switchtwo{A}{B}{}
\hrulefill
Be aware that this variant of \verb|\switchto| does not evaluate its third argument
and that the token-set \verb|\number\value{foobar}| in any case neither does
equal the token \texttt{1$_{12}$} nor does equal the token \texttt{2$_{12}$}:
\newcounter{foobar}
\setcounter{foobar}{1}%
\switchtwo{A}{B}{\number\value{foobar}}
\setcounter{foobar}{2}%
\switchtwo{A}{B}{\number\value{foobar}}
\setcounter{foobar}{3}%
\switchtwo{A}{B}{\number\value{foobar}}
\end{document}
By the way:
None of the tests presented in this answer defines temporary macros.
Therefore the tests presented in this answer are suitable for expansion-contexts also.
E.g., you can do things like \csname @\switchtwo{first}{second}{1}oftwo\endcsname{first}{second}
.
With the tests presented in this answer, the placement of the first and second argument of \switchtwo
is done in a way where unbalanced \csname
/\endcsname
/\if...
/\or
/\else
/\fi
in the arguments don't disturb.
E.g., you can do things like \csname @\switchtwo{\ifx AA}{\ifx AB}{1}first\else second\fi oftwo\endcsname{first}{second}
.
But be aware that brace/group-nesting is independent from \if..
..\else
..\fi
-matching and that therefore such things can disturb the \if..
..\else
..\fi
-matching of surrounding \if..
..\else
..\fi
-constructs.
You can use \ifcase
:
\newcommand{\switchtwo}[3]{%
\ifcase#3 \or#1\or#2\fi
}
The macro will return nothing if the third argument is neither 1 nor 2, but you'll get errors or garbage if the third argument is not an integer.
Your idea can't work, because the positional arguments in a definition are stored in a special way and you can't mix the replacement text with them.