\write16 sends to terminal, \message also does this. Why there are two commands for this and in which cases each one must be used?

  • on can see \message like \immediate\write but there is an other difference that's each write start a new line and \message don't
    – touhami
    Commented Aug 10, 2016 at 5:53
  • TeX by topics page 250
    – touhami
    Commented Aug 10, 2016 at 6:01
  • See The TeXbook, bottom of page 227–top of page 228.
    – GuM
    Commented Aug 10, 2016 at 9:25

2 Answers 2


Here's in D. Knuth's words

An ‘\immediate\write16’ differs from \message in that \write prints the text on a line by itself; the results of several \message commands might appear on the same line, separated by spaces.


First page
\write16{** one **}  \message{** two **}

Second page
\immediate\write16{** one W **}\immediate\write16{** two W **} 
\message{** one M **}\message{** two M **}

sample.log shows

(sample.tex ** two ** [1{[....]/texmfs/data/pdftex/config/pdftex.map}
** one **
** one W **
** two W **
** one M ** ** two M ** [2] )

Well, for the sake of completeness, another difference is that LuaTeX supports more than 16 streams (it supports 128), therefore unlike \message, \write16 might actually write to some code that allocates that stream.

Some alternatives include

  • Lua's print()
  • \write128, which is also valid in other engines
  • \message with ^^J/whatever \newlinechar is at the end
  • LaTeX's \typeout command which internally writes to the \@unused stream.

Remark, morewrites package does not touch stream 16 (it only uses 0-15 and 19...) so 16 is still safe.

Another difference, this one only for academical purpose, is that

  • \message expands tokens as it goes, similar to \csname … \endcsname, \pdfescapestring, \scantokens or \edef.

  • \write16 needs to first collect the arguments unexpanded (like \def or \toks0={…}), then fully expand it (with an \endwrite token put after the }) when it needs to be written.

    \immediate\write16 inherits this behavior as well. (it could do differently, but I assume this is for implementation simplicity)

Consequently, in these cases the behavior is different:

% given this.

% then...
\message{123 \noexpand\someoutertoken}  % works
%\immediate\write16{123 \noexpand\someoutertoken}  % fails

\message{\iffalse}{\fi}  % works
%\immediate\write16{\iffalse}{\fi}   % fails, produces a "incomplete iffalse" error message just like "\iffalse\someoutertoken\fi"

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .