\rule
is not the best tool for comparing \dimen
s with \skip
's, because the plus
or minus
specifications are ignored.
The definition of \rule
is
\DeclareRobustCommand\rule{\@ifnextchar[\@rule{\@rule[\z@]}}%
\def\@rule[#1]#2#3{%
\leavevmode
\hbox{%
\setlength\@tempdima{#1}%
\setlength\@tempdimb{#2}%
\setlength\@tempdimc{#3}%
\advance\@tempdimc\@tempdima
\vrule\@width\@tempdimb\@height\@tempdimc\@depth-\@tempdima}}
The token \@width
stands for width
; since \vrule
requires a \dimen
either explicit or with a register, in the latter cases it coerces a \skip
to a \dimen
.
So the fact that \rule{123pt plus 12pt minus 42pt}{1pt}
works without error is just a consequence of the implementation and the resulting width would be 123pt anyway.
It's better to compare the values you get. Consider
\documentclass{article}
\newlength{\mytest}
\begin{document}
\setlength{\mytest}{\dimeval{\linewidth plus 100pt minus 100pt - 100pt}}
\texttt{\the\mytest}
\setlength{\mytest}{\skipeval{\linewidth plus 100pt minus 100pt - 100pt}}
\texttt{\the\mytest}
\end{document}
where I changed 1cm
into 100pt
in order not to get decimals.

What's that “-100pt” doing at the top? That's the proof your attempts are not equivalent.
Indeed, your
\dimeval{\linewidth plus 100pt minus 100pt - 100pt}
returns 345.0pt, because p
is extraneous to \dimexpr
(on which \dimeval
is based) so in the end LaTeX does
\setlength{\mytest}{345.0pt plus 100pt minus 100pt - 100pt}
which becomes
\mytest=345.0pt plus 100pt minus 100pt - 100pt\relax
(because of the implementation of \setlength
). The part
\mytest=345.0pt plus 100pt minus 100pt
is a complete \skip
specification; then TeX typesets -100pt
.
To the contrary, the argument in \skipeval
is valid for \glueexpr
and the length is computed as expected.
Can the wrong input to \dimeval
be caught? I don't think it's possible without performing assignments, which would make the command unexpandable.