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.

If I am writing a TeX package (as one can find such on CTAN), there are following approaches to define a new dimension length that should be changeable by a user of that package.

  • Approach A: Define an inaccessible dimension with @ and an accessible macro for setting (see also meaning of @)

    \newdimen\PKG@length \PKG@length=5pt
    \def\setPKGlength#1{\PKG@length=#1}
    

    and ask the user to modify the dimension with \setPKGlength{7pt}

  • Approach B: Define an accessible dimension without @

    \newdimen\PKGlength \PKGlength=5pt
    

    and ask the user to modify the dimension with standard techniques like \setlength{\PKGlength}{7pt} in LaTeX or \PKGlength{7pt} in plain TeX (see also What is the right way to set a dimension parameter?).

Which approach is safer to use or has more advantages? Any alternatives?

share|improve this question
3  
I think the answer to your question will depend on what you're trying to do. Are you writing a package? Are there parameters in the package that are necessary for implementation but not at the user level? Who are you writing the code for? And other similar questions. If you can provide a little bit more of context for what you're trying to accomplish, I think you'll get a much more satisfactory answer. –  A.Ellett Jan 20 '13 at 2:48
    
Thx. More info is added in first sentence. Please assume I want to write an package and the package is like one on CTAN. Yes, there are parameters that are used only for implementation, but they are hidden with @ anyway. My question is about a parameter that is used by both, implementation and user. –  e-birk Jan 20 '13 at 12:36
add comment

2 Answers

up vote 18 down vote accepted

Setting a dimension

There are several ways:

  • LaTeX:

    \newcommand*{\setPKGlength}[1]{\setlength{\PKG@length}{#1}}
    

    Advantage: Package calc is automatically supported.

  • e-TeX:

    \def\setPKGlength#1{\PKG@length=\dimexpr(#1)\relax}
    
  • plain-TeX:

    \def\setPKGlength#1{\PKG@length=#1\relax}
    

    Do not forget the final \relax (see Joseph Wright's answer)

Approach A (setter function and internal register name)

Advantages:

  • If the fact that PKGlength uses a TeX dimension register is an implementation detail, then it should be hidden, e.g. by using the @-notation and providing a setter function. Then the internal representation can be easily changed, e.g. using a macro instead of a register.

Disadvantages:

  • An additional macro for setting is needed at least.

  • Without a getter function it is hard to obtain the current value and, thus, it is difficult to set a relative value, e.g. setting the length value to 50% of the current setting.

Approach B (direct dimension register)

Advantages:

  • Fast access without overhead for setting the value.

  • Read access, it is possible to set relative values, e.g.:

    \PKGlength=.5\PKGlength
    

Disadvantages:

  • The dimension register becomes part of the package interface that forbids later changes of the storage type (dimension register, macro, ...).

Setting via key value interface

The question mentions both LaTeX and plain TeX, therefore I am using my packages kvdefinekeys and kvsetkeys that can be used with LaTeX, plain TeX and even iniTeX. Alternatives for LaTeX are keyval, xkeyval, pgfkeys, l3keys, ...

\newdimen\PKG@length
\begingroup\expandafter\expandafter\expandafter\endgroup
\expandafter\ifx\csname RequirePackage\endcsname\relax
  % plain TeX
  \input kvdefinekeys.sty\relax
  \input kvsetkeys.sty\relax
  \begingroup\expandafter\expandafter\expandafter\endgroup
  \expandafter\ifx\csname dimexpr\endcsname\relax
    % without \dimexpr
    \kv@define@key{PKG}{PKGlength}{\PKG@length=#1\relax}%
  \else
    % with \dimexpr
    \kv@define@key{PKG}{PKGlength}{\PKG@length=\dimexpr(#1)\relax}%
  \fi
\else
  \RequirePackage{kvdefinekeys}%
  \RequirePackage{kvsetkeys}%
  \kv@define@key{PKG}{PKGlength}{\setlength{\PKG@length}{#1}}%
\fi
\def\PKGsetup#1{% or \newcommand for \LaTeX
  \kvsetkeys{PKG}{#1}%
}

% usage example
\PKGsetup{PKGlength=5pt}
share|improve this answer
    
A potential advantage of the setter/getter approach may also be its extensibility: If in a future release or another package you need to do THING whenever the dimension is changed (such as recalculate a layout) then this can be accomplished by hooking into the setter. –  Daniel Jan 20 '13 at 18:07
    
@heiko-oberdiek Just a note: Was the edit at Approach A, Disadvantages, from "getter" to "setter" function correct? Maybe the sentence was hold too short and it should read: "Without a getter function it is hard to obtain the current value and, thus, it is difficult to set a relative value, e.g. ......" –  e-birk Jan 20 '13 at 22:04
    
@e-birk You are right, thanks, answer edited accordingly. –  Heiko Oberdiek Jan 21 '13 at 9:29
add comment

Using a specific author interface rather than exposing the internals to the author has the benefits of flexibility for future changes. For example, I as an author, I might have used your macro \setPKGlength{7pt} in five papers.

If this command was used by the package internally and you as the maintainer of the package might have decided to change you macro to \setlengthPKG{7pt} for readability reasons, I will not be able to still process my previous papers.

Exposing an interface rather than internal commands is a common paradigm in many computer languages programming. In the case of TeX/LaTeX it also brings consistency in the equation (internal commands should have an @), external should not have them.

Edit

My own preference is to expose PGF keys style interface for cases where a multitude of parameters are required (see longer example), such as:

\cxset{try textheight/.code=\global\setlength\trytextheight@cx{#1},
   try textheight/.default=\textheight,
   try headheight/.code=\global\setlength\tryheadheight@cx{#1},
   try headheight/.default=\headheight, 
   try headsep/.code=\global\setlength\tryheadsep@cx{#1},
   ....
   try topmargin/.code=\global\setlength\trytopmargin@cx{#1},
   try topmargin/.default=\topmargin,...
}

For simpler cases, setting quick setters and getters is my preferred coding style:

\documentclass{article}
\usepackage{lipsum}
\makeatletter
%  Properties.
\def\ece#1#2{\expandafter#1\csname#2\endcsname}%

% \setproperty@cx{atom}{propertyname}{value} defines the property 
% propertyname  on the ``atom'' atom to have value.

\def\setproperty@cx#1#2#3{\ece\protected@edef{#1@p#2}{#3}}%

% \getproperty@cx{atom}{propertyname} expands to the value of the property
% propertyname on atom.

\def\getproperty@cx#1#2{%
    \expandafter\ifx\csname#1@p#2\endcsname\relax
        \else \csname#1@p#2\endcsname
    \fi
}


\long\def\setminipage@cx#1#2{%
    \setproperty@cx{boxwidth}{width}{\dimexpr#1\relax}%
    \fbox{%
        \minipage{\getproperty@cx{boxwidth}{width}}
            \raggedright #2
        \endminipage
    }%
}

\def\setparindent@cx#1{%
    \setproperty@cx{parindent}{value}{\dimexpr#1\relax}% 
    \parindent\getproperty@cx{parindent}{value}%
    %begins a paragraph if necessary
    \leavevmode
}


% Author command API

\let\SetParagraphIndentation\setparindent@cx
\let\SmallBox\setminipage@cx

\makeatother

\begin{document}

\SmallBox{25pt+35pt}{lorem ipsum dorem. Lorem\par lorem.}

\lipsum[5]
\SetParagraphIndentation{.5in + 2cm + 10pt}
\lipsum[5]
\end{document}
share|improve this answer
2  
The problem of name changing applies to macros as well as parameters. Hence, a stable interface is good and necessary as you said. But what should the interface contain? Macros (approach A) or parameters directly (approach B)? I am not so clear about that from your answer... –  e-birk Jan 20 '13 at 13:01
1  
@e-birk I always prefer a macro and preferably using a key value interface. If LaTeX, I would use PGF keys. Will expand on my answer to make it a bit clearer. –  Yiannis Lazarides Jan 20 '13 at 14:15
    
@e-birk Please see edit. Hope it is now a bit more clear. –  Yiannis Lazarides Jan 20 '13 at 17:46
    
Thank you! Hence, key value interfaces are the state of the art. And otherwise using getter and setter functions to hide the implementation. –  e-birk Jan 20 '13 at 22:22
1  
@e-birk Think of key values as your json implementation for LaTeX:) –  Yiannis Lazarides Jan 21 '13 at 9:41
add comment

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.