# How to add a unit to a command argument?

Currently I set up a box of given length #1 and width #2 like this:

\newcommand{\mybox}[2]{
This is a box of #1 by #2 centimeters:
\framebox{\hbox to #1cm {\vbox to #2cm}}
}

% Usage:
\mybox{5}{8]


However this causes an error as it's not allowed to append cm to the parameters #1 and #2.

Is there a way to append a unit to a command argument? Unfortunately, it is not possible to pass the unit as an argument because I also use the parameters in their original raw form.

-
You shouldn't need \hbox and \vbox here. The optional arguments to the LaTeX \parbox command are designed to specify the required height and width. – David Carlisle Jan 29 '12 at 11:53

You have no content for your second box, and are missing the required brace group:

\documentclass{article}
\newcommand{\mybox}[2]{%
This is a box of #1 by #2 centimeters:
\framebox{\hbox to #1cm {\vbox to #2cm{}}}%
}
\begin{document}
% Usage:
\mybox{5}{8}
\end{document}

-
Thank you for your fast and simple answer! – SecStone Jan 29 '12 at 21:55

Here is a way of doing it, plus an alternative that doesn't use \hbox or \vbox, but zero-width rules rather:

\documentclass{article}
\newcommand{\mybox}[2]{%
This is a box of~#1 by~#2 centimeters:
\framebox{\hbox to \dimexpr#1 cm\relax {\vbox to \dimexpr#2 cm\relax{}}}%
}
\newcommand{\myboxx}[2]{%
This is a box of~#1 by~#2 centimeters:
\fbox{\rule{\dimexpr#1cm\relax}{0pt}\rule{0pt}{\dimexpr#2cm\relax}}%
}
\begin{document}
\mybox{5}{8} \par
\myboxx{2}{2}
\end{document}


The key to modifying your argument from number to dimension is to use \dimexpr. Also, similar to using \hbox to .. {...}, you need to enclose the \vbox to .. {...} with braces as well.

-

A cheap way to add a default unit of measure to an argument is to say

\sbox0{\dimen0=#1cm}


(instead of cm one can use any legal unit of measure). If #1 is a number without a unit attached, the assignment will leave nothing to typeset in the box, which will have zero width. Otherwise cm will be typeset.

So here's a way:

\documentclass{article}
\newcommand\testforunit[2]{%
\sbox0{\dimen#1=#2cm}%
\ifdim\wd0=0pt
\dimen#1=#2cm
\else
\dimen#1=#2\relax
\fi}

\newcommand{\mybox}[2]{%
This is a box of #1 by #2 (default unit centimeters):\hfill
\begingroup\fboxsep=-\fboxrule
\testforunit{0}{#1}\testforunit{2}{#2}%
\framebox[\dimen0]{\rule{0pt}{\dimen2}}%
\endgroup\par}

\begin{document}
\mybox{2}{3}

\mybox{2cm}{3cm}

\mybox{1in}{2in}
\end{document}


With \testforunit we perform the test on #2 adding cm if necessary and store the requested length in \dimen#1. The construction of the box is done with those two length but in a group where \fboxsep is set to \fboxrule, so that the frame will have the exact requested dimensions. In the example the first and second boxes are identical.

As suggested by Joseph, here is the "official" LaTeX kernel way of defining \testforunit:

\makeatletter
\newcommand{\testforunit}[2]{\@defaultunits\dimen#1=#2cm\relax\@nnil}
\makeatother


-
Wouldn't \@defaultunits be as good an approach here (via a \dimen)? – Joseph Wright Jan 29 '12 at 9:56
What about a \dim_set_withdefaultunit:Nnn \l_my_dim { #1 } { cm }? You'll need it, eventually. – egreg Jan 29 '12 at 10:11
I'm not sure we will, actually :-) We have some need for this in implementing the NFSS in expl3, but there it's clear that the default unit is fixed (as pt). – Joseph Wright Jan 29 '12 at 10:32