# Stupid error caused by doing stupid things

When I was writing my thesis I wrote the following two commands which I found useful (and still do). They are both ways of defining other commands.

\usepackage{ifthen}
\makeatletter
\def\optional #1[#2]#3#4{\newcommand{#1}[#2][@rGUmentmiSSing]{\ifthenelse{\equal{##1}{@rGUmentmiSSing}}{#4}{#3}}}
\makeatother


They aren't easy to read. The first one allows me to define a command with an optional argument, where the behaviour of the command is very different if the optional argument is there or not.

The second allows me to define a command with a modifier which I usually use if I have two versions of the same object but one defined on a larger space. For example I have

\optional{\foo}[1]{F(#1)}{F}
\starredcommand{\barr}{\mathcal B}{\mathscr B}


So I can write

\begin{align}
\foo &= \foo[x] \\
\barr &\neq \barr*
\end{align}


Which would give me the same effect as

\begin{align}
F &= F(x) \\
\mathcal B &\neq \mathscr B
\end{align}


I like these commands but they don't play nicely together. For example if I write \foo[\bar] or \foo[\bar*] I get over 100 errors, which is bad. It's not to do with the \@gobble command eating the bracket. \foo[\bar* 123456789] Gives me the same thing. And it's not to do with the square brackets. If I define

\newcommand{\fine}[1][y]{X^{#1}}


then \fine[\bar] works exactly as it's supposed to.

I have no idea what's going wrong. It would be great if someone could help.

Here's a follow up question if that one's too easy. At the moment there's no way of including arguments in my \starredcommand If I wanted to give \barr an argument I'd normally do something like

\makeatletter
\newcommand{\@barr}[1]{\mathcal B^{#1}}
\newcommand{\@barrstar}{\mathscr B^{#1}}
\starredcommand{\barr}{\@barr}{\@barrstar}
\makeatother


Which works fine (even with optional arguments or my \optional command) but it sort of defeats the point of defining the \starredcommand in the first place. I'd love a version of starred command that could work with arguments but I can't think of a way of doing it.

-
why don't you have a look at the xparse package, can do very sophisticated argument parsing very easy. – daleif May 14 '13 at 11:02
@ daleif: That would be far too sensible :) It looks like redefining the two commands using that package is probably the way to go. Thanks! – Tim May 14 '13 at 11:12
Much as I like your question I feel the title would be better if it described the symptom rather than the cause. – Matthew Leingang May 14 '13 at 12:41
@MatthewLeingang point taken, but I couldn't think of a concise way of describing this particular problem. – Tim May 14 '13 at 14:20

A quick attempt with xparse:

\documentclass{article}
\usepackage{xparse,mathrsfs}
\NewDocumentCommand\optional{mO{}mm}
{%
\NewDocumentCommand{#1}{o#2}
{\IfNoValueTF{##1}{#4}{#3}}%
}
\NewDocumentCommand\starredcommand{O{s}mmm}
{%
\NewDocumentCommand{#2}{#1}
{\IfBooleanTF{##1}{#4}{#3}}%
}

\optional{\foo}{F(#1)}{F}
\optional{\baz}[m]{Baz with opt #1 and #2}{Baz without opt and #2}
\starredcommand{\barr}{\mathcal{B}}{\mathscr{B}}
\starredcommand[t{+}]{\carr}{\mathcal{C}}{\mathscr{C}}

\begin{document}
$\foo$

$\foo[x]$

$\foo[\barr*]$

$\foo[\barr]$

$\foo[\carr+]$

$\foo[\carr]$

\baz{x}

\baz[Y]{x}
\end{document}


However you have to change the way arguments are specified. You see in the example how to use a + instead of the *; for \optional and how to define \baz with a mandatory argument (the optional one is always present).

-
Fantastic thank you. That might have taken days to figure out with just manual. I can probably figure out how to do the arguments using this. – Tim May 14 '13 at 11:53

Here is how you can have your \starredcommand with arguments

\documentclass{article}
\usepackage{amsmath}
\usepackage{mathrsfs}
\makeatletter
% Following 3 lines thanks to Prof. Enrico Gregorio, from:
% http://tex.stackexchange.com/questions/42318/
%   removing-a-backslash-from-a-character-sequence
\begingroup\lccode\|=\\
\lowercase{\endgroup\def\removebs#1{\if#1|\else#1\fi}}
\newcommand{\@macro@name}[1]{\expandafter\removebs\string#1}
%
\newcommand\starredcommand[5]{%
\gdef\mname{\@macro@name{#1}}%
\newcommand#1{\@ifstar{\csname @\mname star\endcsname}
{\csname @\mname\endcsname}}
\expandafter\newcommand\csname @\mname\endcsname[#2]{#3}
\expandafter\newcommand\csname @\mname star\endcsname[#4]{#5}
}
\makeatother
\begin{document}

\starredcommand{\barr}{1}{\mathcal #1}{1}{\mathscr #1}

\begin{align}
\barr{C} &\neq \barr*{F}
\end{align}

\end{document}


FOLLOW UP: Here is a version of your \optional command:

\usepackage{ifthen}
% ...
\def\optional#1[#2]#3#4{%
\newcommand#1[#2][]{\ifthenelse{\equal{##1}{}}{#4}{#3}}%
}


though it is not ideal. It does allow, per the user's desire, for \barr to be an argument of foo, except that the \barr must be protected, as in

\optional{\foo}[1]{F(#1)}{F}
$$\foo = \foo[\protect\barr{Q}] \neq \foo[\protect\barr*{R}]$$


-
Also excellent. I'd tried removing the backslashes but given up as impossible. I'm going to use xparse though. It's probably more stable than the code I write. – Tim May 14 '13 at 11:57