This is not a complete answer as I don't know precisely why this happens, unless we account for it as a simple omission in/limitation of the compiler (which it could well be). Nonetheless, I can at least tell you what is happening.
As you know, Compile
has HoldAll
. The fact that the Piecewise
is not evaluated before being seen by Compile
when entered directly as a bracket leads to its translation into slightly different code.
The evaluated form of the Piecewise
is:
Piecewise[{{{0., 0.}, x > 5.}}, {1., 1.}]
Compile
correctly translates this into code completely equivalent to:
If[x > 5., {0., 0.}, {1., 1.}]
However, when faced with the unevaluated form as entered using the bracket, i.e.
Piecewise[{{{0., 0.}, x > 5.}, {{1., 1.}, True}}]
it produces (as you rightly say)
If[x > 5., {0., 0.}, If[True, {1., 1.}, 0]]
which is not compilable due to the obvious mismatch in tensor rank between {1., 1.}
and 0
. We can fix the problem at this stage by substituting {0., 0.}
in place of 0
, but not by simply removing the 0
(as this is interpreted as Null
, which is of a special Null
or "void" type). A better way is simply to remove the redundant nested If
and place the default value directly in the body of the enclosing If
.
Alternatively, we might manually do the same transformation that evaluation effects:
Hold@Compile[{{x, _Real}}, Piecewise[{{{0., 0.}, x > 5.}, {{1., 1.}, True}}]] /.
HoldPattern@Piecewise[{conds__List, {default_, True}}] :>
Piecewise[{conds}, default] // ReleaseHold
However, my personal preference would be to avoid Piecewise
and similar functions when writing compilable code. As we saw above, the compiler cannot work with these directly, instead translating them into nested If
s before compilation. In my opinion, it is much less likely to lead to errors and oddities of the sort encountered here if one uses only constructs that have direct equivalents in bytecode, and hence for which one can predict to a reasonable degree of accuracy what the compiled code will actually be.