3

This question is just for my own understanding of how expansion works.

I'm using the siunitx package in a document. In order to make sure that I'm consistant with myself, I try to write results of measurements as a macro so that I can change them globally from one place.

I noticed that adding a pair of braces {} to the end of one of these macros causes an error from siunitx. Have a look at the following MWE:

\documentclass{article}

\usepackage{siunitx}

\begin{document}

\newcommand{\aMeasurement}{0.9(1)}

% This works fine
The answer was \num{\aMeasurement}.

% This gives an error
The answer was \num{\aMeasurement{}}.

\end{document}

I thought that parameters to macros were fully expanded before the macro was run. If so, how can siunitx possibly tell any difference between these two calls?

  • This has nothing to do with your macro, you would get the same error with \num{123(1){}}. – Ulrike Fischer Jan 5 '18 at 19:38
  • Sometimes the order in which macros expand makes a difference, in which case \expandafter is often used. – John Kormylo Jan 5 '18 at 19:51
  • @UlrikeFischer Huh, you're right. Do you know why? – CharlieB Jan 5 '18 at 19:53
  • apart from any errors parameters of macros are not expanded unless they are met while expanding the body of the macro. but your example has no parameters (other than \num) so the {} forms a group – David Carlisle Jan 5 '18 at 20:07
  • 1
    look in the log never trust an editor to show you tex messages (unless it is emacs:-) – David Carlisle Jan 5 '18 at 20:33
6

Ignoring the specifics of siunitx there appear to be some misunderstandings about TeX's execution order.

Firstly macro parameters are not expanded before a macro call they are only expanded (if at all) if the parameter is met after the macro is expanded.

You can see this in

\def\foo#1{}


\foo{\somethingundefined}

\bye

\somethingundefined is not expanded before calling \foo (which would have generated an error) in fact as \foo does not use #1 the parameter is never expanded at all.

Secondly {} after a macro is not a parameter unless the macro is defined to take a parameter (the macro \aMeasurement in your question does not take a parameter)

After

\def\foo{hbox}


\foo

\foo{}

\foo and \foo{} are not at all equivalent, \foo expands to hbox and \foo{} expands to hbox{} these will take very different code paths for example

\csname\foo\endcsname

would execute the command \hbox but

\csname\foo{}\endcsname

would execute the command with name hbox{} (which being previously undefined would act like \relax)

  • Ah, so the problem was that the macro \aMeasurement{} didn't exist. I tried redefining \aMeasurement to take 1 parameter and indeed it stopped the error from appearing since it now gobbles the {}. Thanks! – CharlieB Jan 5 '18 at 20:26
  • @CharlieB no almost certainly that is not the problem in siunitx I just used that example to show the codes were different. You presumably don't want to define your real macro to have an unused parameter as you would then always have to follow it by {} which would be rather odd. – David Carlisle Jan 5 '18 at 20:28
  • No of course not, that was just a test to see if I was right about the problem. – CharlieB Jan 5 '18 at 20:33
4

You may have been misguided by the fact that when a parameterless macro has to be used in text, it should be followed by something that makes LaTeX to respect the space after it:

\LaTeX has macros

would print no space between the logo and “has”, whereas

\LaTeX{} has macros

prints correctly. However, this empty pair of braces is not swallowed as part of the macro expansion, because TeX knows \LaTeX has no argument, so it doesn't look for one.

It would be different if a macro is defined like

\newcommand{\foo}[1]{vim}

(where the argument is not used) and

\vim{} can't be escaped from

would indeed swallow the braces. For instance, \edef\VIM{\foo{}} would be equivalent to \def\VIM{vim}, because the braces disappear as part of argument substitution. On the other hand,

\vim\ can't be escaped from

would print with no space between “vim” and “can't”, because the argument is now “control space” and the macro throws its argument away.

Your input \num{\aMeasurement{}} is essentially equivalent to

\num{0.9(1){}}

and you receive the error message

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! siunitx error: "invalid-token-in-number"
! 
! Invalid token '\q_recursion_tail ' in numerical input.
! 
! See the siunitx documentation for further information.
! 
! For immediate help type H <return>.
!...............................................  

The invalid token that's referred to is the open brace {. If you scroll past the error, you'll see

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! siunitx error: "invalid-number"
! 
! Invalid numerical input '0.9(1){}'.
! 
! See the siunitx documentation for further information.
! 
! For immediate help type H <return>.
!...............................................  

that should be clear enough: \SIdoesn't like at all the tokens{}`.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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