Got it.
Thanks!
Text Formatting ⇒ Macro Fail
NEW: TikZ book now 40% off at Amazon.com for a short time.

-
- Posts: 139
- Joined: Tue Mar 10, 2015 11:06 am
Macro Fail
Johannes_B wrote:Underlining some space works nicely, but seems a bit strange. How about using the simple and built-inrule
?
Here we use an optional argument to set the length of the line. The default value was set to 1.5em; 150% the width of the letter M.Code: Select all
\documentclass{article} \newlength{\answerlinethickness} \setlength{\answerlinethickness}{.4pt} \newlength{\defaultlinelength} \setlength{\defaultlinelength}{1.5em} \newcommand{\answerline}[1][\defaultlinelength]{\rule{#1}{\answerlinethickness}} \begin{document} And the asnwer is \answerline[2cm]. \begin{displaymath} \begin{array}{r@{= \answerline}} 3+4 \\ 7+1 \\ 47 + 7 \\ \end{array} \end{displaymath} \setlength{\answerlinethickness}{1pt} And the asnwer is \answerline[2cm]. \end{document}
Say I wanted two optional arguments each with their own default. This is how I figured it would be done, but it is not working.
Why not?
And how would I adjust only one of the two defaults?
Code: Select all
\documentclass{article}
\begin{document}
\newlength{\ALT} % ALT=AnswerLineThickness
\setlength{\ALT}{1pt}
\newlength{\DLL} % DLL=DefaultLineLength.
\setlength{\DLL}{1.5cm}
\newcommand{\answerspace}[1][\DLL][2][\ALT]{\rule{#1}{#2}}
\answerspace
\answerspace[5cm][1cm]
\end{document}
Macro Fail
becauseLaTexLearner wrote: Say I wanted two optional arguments each with their own default. This is how I figured it would be done, but it is not working.
Why not?
\newcommand
doesn't provide the means for declaring a macro with two optional arguments, even though \newcommand
itself knows two optional arguments (the number of arguments the to-be-defined macro is to understand and the default value for the first argument---and thus declaring the first argument as optional).
The, hmm, classical approach would be to define a command with only one optional argument and check for a following opening bracket (indicating a second optional argument following) in its body, then call a helper macro that expects two arguments in brackets each:LaTexLearner wrote: And how would I adjust only one of the two defaults?
Code: Select all
\documentclass{article}
\newlength{\ALT} % ALT=AnswerLineThickness
\setlength{\ALT}{1pt}
\newlength{\DLL} % DLL=DefaultLineLength.
\setlength{\DLL}{1.5cm}
\makeatletter% let @ be a letter
\newcommand*\answer@space@ll{}% just for the case the first argument might be empty, say, one wants to call \answerspace with default line length and only change the line thickness
\def\answerspace@intern[#1][#2]{% here, the brackets are mandatory; that's why this command shouldn't be used directly---hence the @ character in its name: from within a LaTeX document body, LaTeX will see `\answer' as a command name, followed by @...
\rule{#1}{#2}%
}
\newcommand*\answerspace[1][\DLL]{%
\ifx\relax#1\relax % if argument for line length is empty
\edef\answer@space@ll{\DLL}% back to default
\else
\edef\answer@space@ll{#1}% else assume valid argument
\fi
\@ifnextchar[% if second opening bracket present
{\answerspace@intern[\answer@space@ll]}% \answer@space@intern can collect the second argument
{\answerspace@intern[\answer@space@ll][\ALT]}% else the second argument's default goes here
}
\makeatother% let @ be something else (again)
\begin{document}
\answerspace % no argument, assuming defaults for line length and line thickness both
\answerspace[5cm][1cm]% two arguments, defining line length and line thickness both
\answerspace[1pc]% one argument, defining line length only and using default for line thickness
\answerspace[][1pc]% two arguments, with the first one empty: using default line length and defining line thickness
\end{document}
Code: Select all
\documentclass{article}
\usepackage{twoopt}
\newlength{\ALT} % ALT=AnswerLineThickness
\setlength{\ALT}{1pt}
\newlength{\DLL} % DLL=DefaultLineLength.
\setlength{\DLL}{1.5cm}
\newcommandtwoopt{\answerspace}[2][\DLL][\ALT]{%
\ifx\relax#1\relax
\rule{\DLL}{#2}%
\else
\rule{#1}{#2}%
\fi
}
\begin{document}
\answerspace
\answerspace[5cm][1cm]
\answerspace[1pc]
\answerspace[][1pc]
\end{document}
Code: Select all
\documentclass{article}
\usepackage{xparse}
\newlength{\ALT} % ALT=AnswerLineThickness
\setlength{\ALT}{1pt}
\newlength{\DLL} % DLL=DefaultLineLength.
\setlength{\DLL}{1.5cm}
\NewDocumentCommand{\answerspace}{O{\DLL}O{\ALT}}{%
\ifx\relax#1\relax
\rule{\DLL}{#2}%
\else
\rule{#1}{#2}%
\fi
}
\begin{document}
\answerspace
\answerspace[5cm][1cm]
\answerspace[1pc]
\answerspace[][1pc]
\end{document}
For calling the macro with only the second optional argument, you could leave the first one empty, but then you must catch this case in your macro (in the examples above done with \ifx\relax#1\relax, where the #1 gets expanded, and if nothing's in this first parameter,
\ifx
compares \relax
with \relax
, which will be true.KR
Rainer
-
- Posts: 139
- Joined: Tue Mar 10, 2015 11:06 am
Re: Macro Fail
Wow, thanks for that amazing response!
It will now take me 18 days to digest it.
It will now take me 18 days to digest it.

- Johannes_B
- Site Moderator
- Posts: 4182
- Joined: Thu Nov 01, 2012 4:08 pm
Macro Fail
The test for an empty optional argument with package etoolbox instead of low level TeX.
Code: Select all
\documentclass{article}
\usepackage{xparse}
\usepackage{etoolbox}
\newlength{\ALT} % ALT=AnswerLineThickness
\setlength{\ALT}{1pt}
\newlength{\DLL} % DLL=DefaultLineLength.
\setlength{\DLL}{1.5cm}
\NewDocumentCommand{\answerspace}{O{\DLL}O{\ALT}}{%
\ifblank{#1}{%
\rule{\DLL}{#2}%
}{%
\rule{#1}{#2}%
}
}
\usepackage{parskip}%for the example
\begin{document}
\answerspace
\answerspace[5cm][1cm]
\answerspace[1pc]
\answerspace[][1pc]
\end{document}
The smart way: Calm down and take a deep breath, read posts and provided links attentively, try to understand and ask if necessary.