Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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? :)

share|improve this question

2 Answers 2

up vote 11 down vote accepted

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
share|improve this answer
    
Thank you very much, that works of course :) –  Sh3ljohn Apr 18 at 16:54

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.
|...............................................
? 
share|improve this answer
    
Your answer is incredible, I didn't even know there was a LaTeX3.. Thank you very much! –  Sh3ljohn Apr 18 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 at 20:55

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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