Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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}}}  
\newcommand{\starredcommand}[4][*]{\newcommand{#2}{\@ifnextchar#1{\expandafter #4\@gobble}{#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.

share|improve this question
4  
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
2  
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

2 Answers 2

up vote 8 down vote accepted

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).

enter image description here

share|improve this answer
    
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}

enter image description here

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}]\)

enter image description here

share|improve this answer
    
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

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.