6

I find myself needing to define many different macros relating to variables, spaces, etc. to help define consistent font choices (\mathsf,\mathcal, normal, etc). These all essentially look like:

\newcommand{\P}{\ensuremath{\mathcal{P}}\xspace}

which lets \P be used in text/math mode, not eat spaces after it, etc. All essentially what I want out of notation definition.

I've abstracted this command system to the following constructor:

\newcommand{\makespace}[2]{\newcommand{#1}{\ensuremath{\mathcal{#2}}\xspace}}

With this macro, I'll have \makespace{\P}{P} produce the first macro I wrote, which makes all of my macro definitions more consistent/readible. I could just leave it at this, but I'll need to define multiple constructors - as an example, something like:

\newcommand{\makeconstant}[2]{\newcommand{#1}{\ensuremath{\mathsf{#2}}\xspace}}

(where \mathcal was replaced with \mathsf) would also need to be defined. So, it seems like making a constructor of constructors would be prudent, which I'd imagine would look like:

\newcommand{\makeconstructor}[2]{\newcommand{#1}[2]{\newcommand{#1'}{\ensuremath{#2{#2'}}\xspace}}}

Here's my issue - I want this two parameter macro to return a two parameter macro. How can I differentiate between #1 and #1' (which I'm sure is the incorrect notation)? What's the correct way to "keep the paramters separate" when defining a higher-order function such as this?

JPi
  • 13,595
  • 5
    Where do I start? I mean, pardon my sincere tone, but you're actually doing three things that should not be done. (1) Use \xspace. (2) Use \ensuremath improperly. (3) Define or re-define one-letter macros for math symbols instead of using more descriptive names. Note that your code would not compile with the error ! LaTeX Error: Command \P already defined. Or name \end... illegal, see p.192 of the manual. – yo' Jun 21 '17 at 17:15
  • 5
    If you want to reference an argument of an inner command, use ##1, if you want to reference an argument of a command inside a command inside a command, use ####1 if you want to ... use ########1 etc. Also, do not redefine one-letter commands, they are reserved. What you do here, is redifining the macro newcommand. This is at least strange. – Michael Fraiman Jun 21 '17 at 17:24
  • @yo' I appreciate the criticism. The \P example actually has name \player in usage, for whatever reason I decided against including that here. As for not using xspace, if I have issues with it eating spaces should I try throwing an {} on the end of whatever is causing issues, and then posting here if that doesn't work? It was introduced to me by one of my coauthors who's quite a bit more senior than me. – Mark Schultz-Wu Jun 21 '17 at 17:27
  • @MichaelFraiman Am I redefining \newcommand, or defining an alternative usage/a template for it? I'm attempting to do the second, but if this would break \newcommand inadvertently that makes this all not worth it. – Mark Schultz-Wu Jun 21 '17 at 17:28
  • @Mark Your use of both xspace and ensuremath is linked. Why not $\player$? – yo' Jun 21 '17 at 17:34
  • @Mark you use a command that calls \newcommand, which can be considered unsafe. – Michael Fraiman Jun 21 '17 at 17:34
  • @yo' I agree that \xspace in this example is undesirable. However, it can be very useful. For instance, in todonotes \todo gobbles up the space after it. It's innocuous to redefine \todo to include an \xspace since todo notes won't appear in the final manuscript, anyway. – JPi Jun 21 '17 at 17:37
  • @MichaelFraiman I don't think this use case is unsafe: it's no different than the kind of macro we would use in a package to create an internal macro from a user-facing macro. These are clearly intended to be used in the preamble to set up shorthands. – Alan Munn Jun 21 '17 at 17:37
  • @yo' I was unaware that \xspace and \ensuremath were considered bad form, and just from a readability of code standpoint preferred \player. – Mark Schultz-Wu Jun 21 '17 at 17:39
  • @MichaelFraiman the intent with defining these is that it makes aesthetic decisions (regarding which of \mathsf, \mathcal, etc to wrap things in) more fluid/easily implemented, and making the section of the preamble where all this notation is actually defined slightly less verbose. – Mark Schultz-Wu Jun 21 '17 at 17:47
  • @Mark i will post an answer then based on your last comment. – Michael Fraiman Jun 21 '17 at 17:49
  • 1
    @MichaelFraiman your comments here are incorrect sorry, the suggested definition does not redefine \newcommand (and single letter names are not in general reserved) – David Carlisle Jun 21 '17 at 18:19
  • @DavidCarlisle I don't mean it redefines 'newcommand', but it does the same as it. – Michael Fraiman Jun 21 '17 at 18:20
  • @MichaelFraiman I think you misunderstood the intended use. See my example which demonstrates the working version. – David Carlisle Jun 21 '17 at 18:22
  • @DavidCarlisle maybe i misunderstood the question. – Michael Fraiman Jun 21 '17 at 18:24

3 Answers3

11

Abstract also the formatting command

\newcommand{\newdescriptor}[3]{\newcommand{#1}{#2{#3}}}

Then

\newdescriptor{\sP}{\mathbf}{P}

will do

\newcommand{\sP}{\mathbf{P}}

Nowhere I see any improvement over the direct definition unless you do a further abstraction step:

\newcommand{\whatever}[1]{\mathbf{#1}}
\newcommand{\constant}[1]{\mathsf{#1}}

\newcommand{\newdescriptor}[3]{\newcommand{#1}{#2{#3}}}

\newdescriptor{\sP}{\whatever}{P}
\newdescriptor{\cs}{\constant}{S}

Add \ensuremath and \xspace if you really want. I will never be convinced that typing

The constant \cS is nice

is better than typing

The constant \(\cS\) is nice

To be honest, I find the second way the only good one (on par with $\cS$).

egreg
  • 1,121,712
9

In the replacement text of a definition #2 is replaced by the second argument, #1 is replaced by the first argument, and ## is replaced by # so

enter image description here

\documentclass{article}
\usepackage{xspace}
\newcommand{\makeconstructor}[2]{%
\newcommand{#1}[2]{\newcommand{##1}{\ensuremath{#2{##2}}\xspace}}}

\makeconstructor\makespace\mathcal
\makeconstructor\makewidget\mathsf

\makespace\SP{P}
\makespace\SQ{Q}
\makewidget\WP{P}
\makewidget\WQ{Q}


\begin{document}

$\SP<\SQ<\WP<\WQ$

\end{document}
David Carlisle
  • 757,742
1

Based on the comments, the main problem can be solved with defining new "style" of typesetting. To change everything with one click, we can now edit one line in preamble.

\documentclass{article}

\newcommand{\mystyle}[1]{\mathcal{#1}} \newcommand{\player}{\mystyle{P}}

\begin{document}

\noindent
Here is calligrafic font.
\[
\player
\]
Oops, seems like now I want all letters to be Sans Serif.

\renewcommand{\mystyle}[1]{\mathsf{#1}}
\[
\player
\]

\end{document}

Here is the result. enter image description here