5

I am writing a command \newrow to generate one row in a longtable. The problem is that the tabular environment here can not see the value of \subColWid (output is 0pt). This occurs only when multirow is also used. Can anyone help me to figure out why the updated \subColWid by \setlength is invisible in the tabular (including column specification). Thanks.

\documentclass{article}

\usepackage{fullpage}
\usepackage{longtable}
\usepackage{array}
\usepackage{multirow}

% define my macros
\newlength{\firstColWid}
\newlength{\secondColWid}
\newlength{\subColWid}
\setlength\firstColWid{0.1\textwidth}
\setlength\secondColWid{0.9\textwidth}
%\setlength{\subColWid}{0.5\secondColWid} % uncomment this line to see correct result

\setlength{\tabcolsep}{0pt}

\newcolumntype{M}[1]{>{\centering\arraybackslash}m{#1}}

\newcommand{\newrow}[2]{ % a command to produce a row spanning two lines
    % set width for each cell in the second column
    \setlength\subColWid{0.2\secondColWid} % this has effect here but not in the 
    %tabular
    % \the\subColWid
    \multirow{2}{*}{#1}  & subColWid = \the\subColWid \\ \cline{2-2}
                         & 
    % use a tabular to represent all the remaining values
    \begin{tabular}[c]{ @{\extracolsep{\fill}} *{2}{M{\subColWid} | }}
        % subColWid = \the\subColWid & #2 \\
        #2 & \the\subColWid \\
    \end{tabular}

}


\begin{document}
\begin{longtable}[c]{|M{\firstColWid}|@{\extracolsep{\fill}} M{\secondColWid}|} % 
    \hline
    % give row number and another cell
    \newrow{1}{Row1} \\ \hline
    \newrow{2}{Row2} \\
    \hline

\end{longtable}
\end{document}
  • Welcome to TeX.SX! The problem probably is, that you try to set lengths in a table cell ... this is possible, but a table cell is a TeX group and as such, lengths settings hold only within a group, not outside, i.e. they will not survive the change from one cell to the next one – user31729 Nov 5 '14 at 4:48
  • Your comment makes much sense for me. But I am still trying to understand the effect scope of TeX macros using the rules extablished by other languages such as C and Perl. Therefore, I guess that \subColWid is a global macro for the document, and that it can be changed by any commands/macros and the effect propogates to other macros/commands using the macro. Your explanation falsifies my guessing. Does it mean each cell group makes a local copy when it changes the value? Thank you very much. – ZZG Nov 5 '14 at 5:15
  • It would be better to think that \subColWid is assigned a value which is realized when it's expanded. LaTeX (and TeX) have only two levels: global and local. By which I mean, if it's not local, then it's global. Here a longish explanation. – A.Ellett Nov 5 '14 at 5:40
2

You might think to prefix \setlength with \global and expect to get the effect you want. And in this particular case, this seems to work. But not generally. See the update below for more details.

\documentclass{article}

\usepackage{fullpage}
\usepackage{longtable}
\usepackage{array}
\usepackage{multirow}

% define my macros
\newlength{\firstColWid}
\newlength{\secondColWid}
\newlength{\subColWid}
\setlength\firstColWid{0.1\textwidth}
\setlength\secondColWid{0.9\textwidth}
%\setlength{\subColWid}{0.5\secondColWid} % uncomment this line to see correct result

\setlength{\tabcolsep}{0pt}

\newcolumntype{M}[1]{>{\centering\arraybackslash}m{#1}}

\newcommand{\newrow}[2]{ % a command to produce a row spanning two lines
    % set width for each cell in the second column
    \global\setlength\subColWid{0.2\secondColWid} % this has effect here but not in the 
    %tabular
    % \the\subColWid
    \multirow{2}{*}{#1}  & subColWid = \the\subColWid \\ \cline{2-2}
                         & 
    % use a tabular to represent all the remaining values
    \begin{tabular}[c]{ @{\extracolsep{\fill}} *{2}{M{\subColWid} | }}
        % subColWid = \the\subColWid & #2 \\
        #2 & \the\subColWid \\
    \end{tabular}

}


\begin{document}

\begin{longtable}[c]{|M{\firstColWid}|@{\extracolsep{\fill}} M{\secondColWid}|} % 
    \hline
    % give row number and another cell
    \newrow{1}{Row1} \\ \hline
    \newrow{2}{Row2} \\
    \hline

\end{longtable}
\end{document}

Of course, that will effect how \subColWid will behave in the remainder of the document. If you need the old value, you should do something like

\newlength\myoldlength
\setlength\myoldlength{\subColWid}

and once you're done with your table you can restore the old value using

 \setlength\subColWid{\myoldlength}

UPDATE

After reading around a bit here (on account of what @egreg wrote regarding the use of \global and \setlength here [see the end of his discussion to see the relevant comment]), my use of \global\setlength above works only idiosyncratically within LaTeX. A better solution is offered by @AndrewSwann here. So it seems a better approach to getting \subColWid to have the desired value, when changing it from within the table, is to do define your command as follows:

\newcommand{\newrow}[2]{ % a command to produce a row spanning two lines
    % set width for each cell in the second column
    \global\subColWid=\dimexpr0.2\secondColWid\relax % this has effect here but not in the 
    %tabular
    % \the\subColWid
    \multirow{2}{*}{#1}  & subColWid = \the\subColWid \\ \cline{2-2}
                         & 
    % use a tabular to represent all the remaining values
    \begin{tabular}[c]{ @{\extracolsep{\fill}} *{2}{M{\subColWid} | }}
        % subColWid = \the\subColWid & #2 \\
        #2 & \the\subColWid \\
    \end{tabular}
}
  • Thank you so much for the quick and great answer. It works now. Could you please tell me a bit more Tex mechanism why my original command does not work and why your suggestion works? I am very confused by Tex Macros and have read many posts, ending up without understanding why my command fails. – ZZG Nov 5 '14 at 5:04
  • There are numerous posts on this site about macros which will be much more helpful than anything I could possibly write here. What took me a long time to get clear on was how macro work via expansion: my mind kept wanting to think of them functionally like in a Perl script or something---that's just completely wrong headed and ultimately gets you into all kind of trouble. – A.Ellett Nov 5 '14 at 5:33
  • What's happening here with your table is an issue of grouping. The cells in the tables are individually grouped. So your assignment of a new value to the length is taking place locally and is not visible outside of the group within which the assignment is taking place. There are various commands for breaking out of a local context: in this situation we can happily apply a \global prefix to the assignment to make the new value visible outside of the current group. – A.Ellett Nov 5 '14 at 5:35
  • Thank you for updating the approach. Just like you mentioned, I always think LaTex macros as Perl variables, which leads me to troubles. Could you please refer me to some materials which I can understand how macros are expanded? In particular, I do not understand why changing value of global macro (defined in preamble) in one group does not have effect in other groups, unless the same-name macro in different groups refer to different things. – ZZG Nov 5 '14 at 18:13
  • I would recommend you read the section on token expansion from TeX by Topic. This very useful guide comes with most LaTeX distributions. If you have access to the command line, you can open this document by running texdoc topic. I'd recommend you read the sections on macro expansion. Otherwise, this is a very broad topic and is probably best answered via another question (or the next time you get stuck). – A.Ellett Nov 5 '14 at 19:15

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.