3

I had a similar problem as this one: Space after LaTeX commands

My first attempt was something like this:

\newcommand{\satip}{SAT\textgreater IP}

This leads to the known Problem, that spaces after the command are eaten up:

\satip is a cool Protocol. %Produces: SAT>IPis a cool Protocol.
                             space missing ^^^

I searched around and found the mentioned Question. The provided solutions helped a lot, but I wasn't completely happy with any of them. \satip/ just looks a little bit strange in a latex document, I like \satip{} much more. It's just, if I forget to put {} behind the command, the space is missing in output. Therefor I'd like to get an error if I use it wrong.

Possible Solution:

\def\satip#{SAT\textgreater IP}
%\satip is a cool Protocol. %doesn't compile, error

This way the open brace is enforced, but the braces can contain something:

\satip{is} a cool Protocol.

This compiles well, but as it doesn't make any sense, I'd like it to produce an error. My current way to handle the Problem is this:

\expandafter\def\csname satip{}\endcsname \relax{SAT\textgreater IP}
\def\satip#1{\csname satip{}\endcsname #1\relax}

%\satip{is} a cool Protocol. %Use of \satip{} doesn't match its definition.
%\satip is a cool Protocol. %Use of \satip{} doesn't match its definition.
\satip{} is a cool Protocol. %works

Now my Question:

This Macro needs a second expansion step. Could that cause any trouble? Are there other Problems? (As I haven't found this anywhere before.)

PS: Sorry for the bad title, I didn't came up with something better. Feel free to edit.

T S
  • 133
  • If anyone wants to play around: [https://www.overleaf.com/4337209grgmrz] – T S Feb 14 '16 at 22:42
  • 1
    I would just use \satip\, and I don't see why \satip{is} should produce an error with that definition. – Paul Gessler Feb 14 '16 at 22:51
  • Mmm... you can always use \satip{} is a cool protocol with your first definition \newcommand*\satip{SAT\textgreater IP}, no need to define it obscurely. – Manuel Feb 14 '16 at 22:51
  • 1
    The most efficient solution is \satip\ . If you really want an error, \def\satip/ is a reasonable way to go, and surely easier to write than \satip{}. And of course in the right circumstances, the \xspace package may be an option, though it is not always the right choice (there's a question on comp.text.tex about this). – jon Feb 14 '16 at 23:02
  • @PaulGessler \satip{ip} doesn't produce an error, but i want it to produce an error, since this usage doesn't make any sense. (i'm not good with english, how can i say it more clearly?) – T S Feb 14 '16 at 23:05
  • @TS it makes perfect sense: ip (a brace-delimited group) is typeset immediately following the expansion of macro \satip. Whether that is what you want is another matter, but in terms of how (La)TeX works, it's perfectly valid usage. – Paul Gessler Feb 14 '16 at 23:12
  • Ahh sorry, my english is too bad. Yes, for LaTeX is perfectly ok, but it doesn't make any sense to me in the context where it is used. – T S Feb 14 '16 at 23:19
  • Since you are using {} as a conceptual delimiter for the control sequence, any deviation from {} should raise an error. \satip{\relax} compiles just fine. Also, you have no way of knowing if you are overwriting an existing control sequence with the name satip or (less likely) satip{} by using \def. – Guho Feb 14 '16 at 23:35
  • @Guho I haven't thought about \satip{\relax} thanks. In the final version I wanted to guard the definition with \@ifundefined or similar... – T S Feb 14 '16 at 23:53
  • @TS great question! I amended the answer you linked in your question to clarify the behavior of #{. Might be of interest. – Guho Feb 15 '16 at 00:43

2 Answers2

3

You can always use

\newcommand*\satip{SAT\textgreater IP}
\satip{} is a cool protocol

I don't see the problem.


By the way, your last definition defines de macro with name satip{} (braces included in the macro name) to be followed by a \relax token. If you put the #1 between \endcsname and \relax in the \satip macro it can only work if #1 is empty (i.e., only if empty braces are given \satip{} is...).


May be this achieves what you want?

\newcommand*\satip[1]
 {\if\relax\detokenize{#1}\relax
    SAT\textgreater IP%
  \else
    \GenericError{} % <- I don't know what this argument does
       {Wrong use of \string\satip{}.} % <- short version
       {Wrong use of \string\satip. You must use \string\satip\space followed by an empyt argument `{}'.}% <- long version
  \fi}
Manuel
  • 27,118
  • I knew of the fact, that the macro satip{} is defined (additional to satip), but didn't expect any problems with this, are there any? – T S Feb 14 '16 at 23:09
  • Reading your comment above: you want to use \satip{} is a cool... but you want to ensure that {} is empty, i.e. not \satip{is} a cool...? – Manuel Feb 14 '16 at 23:11
  • YES!! (my englisch is to bad, sorry that this wasn't clear...) – T S Feb 14 '16 at 23:18
  • 2
    \newcommand*\satip[1]{SAT\textgreater IP\if\relax\detokenize{#1}\relax\else\PackageError{ts}{wrong use of \string\satip.}{Definitely wrong use of \string\satip{}.}\fi} but I don't get why would you want that. In TeX a {} following \satip doesn't mean it's an argument of \satip. – Manuel Feb 14 '16 at 23:37
  • That actually works, thanks. I haven't thought about "In TeX a {} following \satip doesn't mean it's an argument of \satip". That makes it obvious why \def\satip#{...} is ok or even better. – T S Feb 14 '16 at 23:46
3

I wouldn't use {} in the name of the auxiliary macro, but the method is sound:

\newcommand{\satip}[1]{\csname satip\string+\endcsname #1\relax}
\expandafter\def\csname satip\string+\endcsname\relax{%
  SAT\textgreater IP%
}

will trigger an error in case \satip{x} is used

! Use of \satip+ doesn't match its definition.
<argument> x

However \satip ip wouldn't. You should do two steps:

\newcommand{\satip}{}% initialize
\protected\def\satip#{\csname satip\string+\endcsname}
\expandafter\def\csname satip\string+\endcsname#1{%
  \csname satip\string+\string+\endcsname #1\relax
}
\expandafter\def\csname satip\string+\string+\endcsname\relax{%
  SAT\textgreater IP%
}

Now both \satip x and \satip{x} would trigger errors:

! Use of \satip doesn't match its definition.
l.14 \satip x

? 
! Use of \satip++ doesn't match its definition.
<argument> x

l.16 \satip{x}

? 

Note \protected in front of the definition of \satip, so it wouldn't be expanded in “moving arguments” contexts.

An abstract version:

\documentclass{article}

\makeatletter
\newcommand\definestringcommand[2]{%
  \@ifdefinable#1{\@definestringcommand#1{#2}}%
}

\newcommand{\@definestringcommand}[2]{%
  \begingroup
  \escapechar=\m@ne % get rid of the backslash
  % require brace
  \protected\xdef#1##{\expandafter\noexpand\csname\string#1\string+\endcsname}%
  % examine the argument
  \expandafter\xdef\csname\string#1\string+\endcsname##1{%
    \expandafter\noexpand\csname\string#1\string+\string+\endcsname##1\relax
  }%
  \expandafter\gdef\csname\string#1\string+\string+\endcsname\relax{#2}%
  \endgroup
}
\makeatother

\definestringcommand{\satip}{SAT\textgreater IP}

\begin{document}

\satip is nice

\satip{x} is nice

\satip{} is nice

\end{document}

Whether this is useful, I leave the decision to you.

A different implementation: check for the {, then check for a following } eating up both tokens in case of success.

\documentclass{article}

\makeatletter
\newcommand\definestringcommand[2]{%
  \@ifdefinable#1{\@definestringcommand#1{#2}}%
}

\newcommand{\@definestringcommand}[2]{%
  \begingroup
  \escapechar=\m@ne % get rid of the backslash
  % require brace
  \protected\xdef#1##{%
    \expandafter\noexpand\csname\string#1\string+\endcsname
  }%
  \expandafter\gdef\csname\string#1\string+\endcsname{%
    #2%
    \afterassignment\@checkrightbrace\let\@forget= % the space counts
  }
  \endgroup
}
\newcommand{\@checkrightbrace}{%
  \@ifnextchar\egroup{\let\@forget= }{\@strcmderr\let\@forget= }%
}
\newcommand{\@strcmderr}{%
  \@latex@error{Non empty group}{The braces must contain nothing}%
}
\makeatother

\definestringcommand{\satip}{SAT\textgreater IP}

\begin{document}

\satip is nice

\satip{x} is nice

\satip{} is nice

\end{document}
egreg
  • 1,121,712
  • 1
    Why should \satip ip produce no error? Isn't i the argument in this case? Here it produces an error: [https://www.overleaf.com/4337962szgjcf] – T S Feb 15 '16 at 00:12
  • 1
    @TS Yes, it would; but not because a brace is missing. I was still thinking to the \def\satip# method. – egreg Feb 15 '16 at 00:19
  • ahh ok, thanks. What's the benefit of using + in the name of the auxiliary macro? with {} the correct usage \satip{} shows up in the error message "Use of \satip{} ..." (at least in some way) – T S Feb 15 '16 at 00:20
  • 1
    @TS The benefit is having a macro name that can't be ordinarily produced. The idea with {} is interesting, though I'd not use it. But it's your code, not mine. ;-) I'd simply go with \newcommand{\satip}{SAT\textgreater IP}, to be honest. – egreg Feb 15 '16 at 00:21
  • 1
    Can the macro name satip{} be produced "ordinarily"? (I assume "ordinarily" means without \csname) – T S Feb 15 '16 at 00:30
  • @TS If you rewrite the parser so that it treats {} other than TeX treats it, you mean? – cfr Feb 15 '16 at 03:14
  • @cfr No. From egreg's comment I got the impression, that using the macro name satip+ has the benefit, that it "can't be ordinarily produced". I thought this means, that if I write \satip+ the + is not part of the macro name. If I compare this to the macro name satip{}, I assumed it's the same, because in \satip{} the {} also isn't part of the macro name. Therefor I don't get it, whats the benefit of using +? – T S Feb 15 '16 at 11:42
  • The + is part of the name @TS. – cfr Feb 15 '16 at 20:24
  • If one writes \csname satip\string+\endcsname the + is part of the name, but if I just write \satip+, I thought the macro name was satip with + as argument. Am I wrong? – T S Feb 15 '16 at 21:45
  • @TS That's right – egreg Feb 15 '16 at 21:50
  • Ok, but isn't this the same with \csname satip{}\endcsname where {} is part of the macro name and \satip{} where {} is not part of the macro name? – T S Feb 15 '16 at 21:55