20

Sorry this might be a very simple question, I am trying to cleanup a style file, and would like to write a command that basically runs the following code:

\newlength{<name>}\setlength{<name>}{<value>}

Based on another command that runs a \def, I though I'd be able to use expandafter and csname easily; here is what I tried:

\newcommand{\deflen}[2]{%
    \expandafter\newlength{%
    \csname #1\endcsname}\setlength{%
    \csname #1\endcsname}{#2}
}

Unfortunately, this seems to generate an error related to csname being already defined. I think it means that I can't use csname twice in the same expand, but I don't know how to define the name first, and then use it twice... Help? :)

17

You need to assemble the control sequence name before defining with \newcommand, and before using it. This can be achieved using \expandafter twice.

\newcommand{\deflen}[2]{%      
    \expandafter\newlength\csname #1\endcsname
    \expandafter\setlength\csname #1\endcsname{#2}%
}

\deflen{mylength}{12pt}

\showthe\mylength
| improve this answer | |
10

Ian Thompson's code is good, but you could add the check whether you can define a new length in the first place; calling, say,

\deflen{textwidth}{6pt}

would issue an error message at \newlength, but it would set \textwidth nonetheless. Since you are in a style file you don't need \makeatletter for @ commands, so you can do

\newcommand{\deflen}[2]{%
  \expandafter\@ifdefinable\csname #1\endcsname{\prefix@deflen{#1}{#2}}%
}
\newcommand{\prefix@deflen}[2]{%
  \expandafter\newlength\csname #1\endcsname
  \expandafter\setlength\csname #1\endcsname{#2}%
}

The code given as second argument to \@ifdefinable is executed only if the control sequence given as first argument is undefined; otherwise an error is raised and the code is ignored.

Note that prefix stands for the prefix used in the style file for not clobbering other packages' macros.

A LaTeX3 version could be

\RequirePackage{xparse}
\ExplSyntaxOn

\NewDocumentCommand{\deflen}{ s m m }
 {
  \IfBooleanTF { #1 }
   { \prefix_deflen:nnn { dim }  { #2 } { #3 } }
   { \prefix_deflen:nnn { skip } { #2 } { #3 } }
 }

\cs_new_protected:Npn \prefix_deflen:nnn #1 #2 #3
 {
  \cs_if_exist:cTF { #2 }
   {
    \msg_error:nnn { package } { already~defined } { #2 }
   }
   {
    \__prefix_deflen:nnn { #1 } { #2 } { #3 }
   }
 }
\cs_new_protected:Npn \__prefix_deflen:nnn #1 #2 #3
 {
  \use:c { #1_new:c } { l_prefix_#2_#1 }
  \use:c { #1_set:cn } { l_prefix_#2_#1 } { #3 }
  \cs_set_eq:cc { #2 } { l_prefix_#2_#1 } % user level name
 }

\msg_new:nnnn { package } { already~defined }
 {
  Control~sequence~\exp_not:c { #1 } already~defined.
 }
 {
  The~control~sequence~\exp_not:c { #1 } already~exists.~
  Please~use~a~new~name;~the~command~will~not~be~executed.
 }

\ExplSyntaxOff

Note that \deflen{foo}{6pt} will define \l_prefix_foo_skip as the internal name of the register, but also \foo at the user level. The *-version would allocate a rigid length register (a \dimen, in TeXspeak).

Test code:

\deflen{foo}{3pt}
\showthe\foo
\show\foo

\deflen*{baz}{3pt}
\showthe\baz
\show\baz

\deflen{textwidth}{3pt}

Here's the terminal output:

> 3.0pt.
l.40 \showthe\foo

? 
> \foo=\skip47.
l.41 \show\foo

? 
> 3.0pt.
l.44 \showthe\baz

? 
> \baz=\dimen133.
l.45 \show\baz

? 

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! package error: "already defined"
! 
! Control sequence \textwidth already defined.
! 
! See the package documentation for further information.
! 
! For immediate help type H <return>.
!...............................................  

l.46 \deflen{textwidth}{3pt}

? h
|'''''''''''''''''''''''''''''''''''''''''''''''
| The control sequence \textwidth already exists. Please use a new name; the
| command will not be executed.
|...............................................
? 
| improve this answer | |
  • Your answer is incredible, I didn't even know there was a LaTeX3.. Thank you very much! – Jonathan H Apr 18 '14 at 20:53
  • @Sh3ljohn There's not yet a LaTeX3, but its programming layer is already usable along with current LaTeX. As you see, there's no visible \expandafter. Once one gets the hang of it, programming is really easier. – egreg Apr 18 '14 at 20:55

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.