# Changing \newcommand into xparse \NewDocumentCommand

I would like to change the \newcommand \shcpoint into an xparse \NewDocumentCommand. How can I achieve this?

\newcounter{totalpoints}
\regtotcounter{totalpoints}

\newcommand{\shcpoint}[1]{%
\ifnum#1<2
(\emph{#1 point})\hphantom{\em s}%
\else
(\emph{#1 points})%
}


This is my attempt:

\NewDocumentCommand{\shcpoint}{ m }
{%
\ifnum#1<2
(\emph{#1 point})\hphantom{\em s}%
\else
(\emph{#1 points})%
}


My question then extends to: Is there something equivalent to \addtocounter, \ifnum, \else and \fi in LaTeX 3 syntax?

-
Take a quick look at texdoc expl3; it's worth it –  Sean Allred Feb 12 at 16:01
@SeanAllred Looking at it right now. Thnx –  azetina Feb 12 at 16:03
My apologies; texdoc interface3. I really should stop looking at TeX.SX first thing in the morning :-) –  Sean Allred Feb 12 at 16:42

You don't really gain much if you measure in terms of code. The gain is in flexibility and clarity. Here's a possible implementation:

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\shcpoint}{ m }
{
\azetina_shcpoint:n { #1 }
}

\NewDocumentCommand{\printtotal}{ }
{
\int_to_arabic:n { \g_azetina_totalpoints_int }
}

\int_new:N \g_azetina_totalpoints_int

\cs_new_protected:Npn \azetina_shcpoint:n #1
{
\int_compare:nTF { #1 < 2 }
{
(\emph{#1 ~ point})\hphantom{\em s}
}
{
(\emph{#1 ~ points})
}
}
\ExplSyntaxOff

\begin{document}

\shcpoint{1} X

\shcpoint{3} X

\shcpoint{1} X

Total points: \printtotal

\end{document}


Some points to note.

1. When a command defined with \NewDocumentCommand does more than can be implemented with user level commands, it should call a programmer's level function.

2. Since we want to enter the programming environment, we need to issue \ExplSyntaxOn.

3. Since your counter totalpoints is used to keep track of the points and not for typesetting values other than at the end, I declare it as an integer (global) variable.

4. I define also the command for printing the variable's value; since it uses just one internal function, it's not necessary to define our own internal.

5. In the programming environment spaces are ignored (unless they are syntactically meaningful for separating command names), so a space in output is usually denoted by ~.

6. The internal function has one argument, so its name ends in :n.

7. \azetina_shcpoint:n is “protected” because it performs an assignment.

8. We do an “integer comparison”:

\int_compare:nTF { <condition> }
{
<true case>
}
{
<false case>
}


David Carlisle correctly points out that there can be a tiny difference when “point” or ”points” is used. Here's a modified version of the code that shouldn't have the problem and also illustrate a further point: the comparison can also be

\int_compare:nT { <condition> } { <true case> }


omitting the false case if nothing should be done. Here we measure the text with the “s” (assuming that the number of points per question is less than 10 and using 0 as the default width for the digits) and typeset the final result in a box of the correct width.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn
\NewDocumentCommand{\shcpoint}{ m }
{
\azetina_shcpoint:n { #1 }
}

\NewDocumentCommand{\printtotal}{ }
{
\int_to_arabic:n { \g_azetina_totalpoints_int }
}

\int_new:N \g_azetina_totalpoints_int
\box_new:N \l_azetina_points_box
\cs_new_protected:Npn \azetina_shcpoint:n #1
{
\hbox_set:Nn \l_azetina_points_box { (0 ~ \textit{points}) }
\makebox[\box_wd:N \l_azetina_points_box][l]
{
(\textit{#1 ~ point\int_compare:nT { #1 > 1 } { s }})
}
}
\ExplSyntaxOff

\begin{document}

\shcpoint{1} X

\shcpoint{3} X

\shcpoint{1} X

Total points: \printtotal

\end{document}


If you try with \showoutput, you can see that all the relevant boxes have width 42.7429pt.

-
Interesting approach with LaTeX 3 syntax. I will study your code and read the expl3 documentation that @SeanAllred suggested. –  azetina Feb 12 at 16:42
Will foo ~ bar between \ExpSyntaxOn … \ExpSyntaxOff “expand” to something like foo bar or foo~bar in the document? In case we want an usual (breakable) space what should we do? foo \ bar? –  Manuel Feb 12 at 18:22
@Manuel foo ~ bar in the programming environment is the same as foo bar in the usual setting. If you want an unbreakable space in the programming environment, use \nobreakspace –  egreg Feb 12 at 18:36

The current expl3 programming layer is really aimed below this, so \addtocounter is fine I think. However the code doesn't do what I guess is the intention of setting point or points to the same width. Also it should be using \textit (or better \itshape) rather than \emph.

\sbox0{\emph{points}\quad}\showthe\wd0


produces

> 36.63177pt.

?
> 36.75957pt.


Which as you see are not equal. To see why consider

\documentclass{article}

\begin{document}

\showoutput

\end{document}


which produces

....\hbox(0.0+0.0)x15.0
....\OT1/cmr/m/n/10 1
....\glue 3.33333 plus 1.66666 minus 1.11111
....\OT1/cmr/m/it/10 p
....\kern-0.51112
....\OT1/cmr/m/it/10 o
....\OT1/cmr/m/it/10 i
....\OT1/cmr/m/it/10 n
....\OT1/cmr/m/it/10 t
....\OT1/cmr/m/it/10 s
....\kern 0.82082
....\penalty 10000
....\glue(\parfillskip) 0.0 plus 1.0fil
....\glue(\rightskip) 0.0
...\glue(\parskip) 0.0 plus 1.0
...\glue(\baselineskip) 3.50197
...\hbox(6.55359+1.94444)x345.0, glue set 294.9071fil
....\hbox(0.0+0.0)x15.0
....\OT1/cmr/m/n/10 2
....\glue 3.33333 plus 1.66666 minus 1.11111
....\OT1/cmr/m/it/10 p
....\kern-0.51112
....\OT1/cmr/m/it/10 o
....\OT1/cmr/m/it/10 i
....\OT1/cmr/m/it/10 n
....\OT1/cmr/m/it/10 t
....\kern 0.94861
....\hbox(0.0+0.0)x4.08887
....\penalty 10000
....\glue(\parfillskip) 0.0 plus 1.0fil
....\glue(\rightskip) 0.0


Where you can see the difference is the different \kern which is the italic correction (added by \emph) for s and t respectively. You would see an even bigger difference if the trailing command had been . rather than \quad as then the italic correction would be suppressed in the first case but not the second.

In this case you could use

{\itshape points}\quad}


and

{\itshape point}\hphantom{\itshape s}\quad}


But that relies on there being no kern specified in the font metrics between t and s.

a safer construct would be

\settowidth\dimen@{\itshape points}%

@azetina You probably made the mistake of looking at the pdf output rather than \showoutput output. I don't ever do that, the log is far more revealing:-) –  David Carlisle Feb 12 at 16:45