# If doesn't compile if its output is the output of Compile?

The smallest sample I can find to reproduce this problem is:

test = Compile[{}, If[True, 1]];
<< CompiledFunctionTools`
CompilePrint@test
…………
1    R0 = MainEvaluate[ Function[{}, If[True, 1]][ ]]
2    Return

The problem disappears when the If[] is followed by a semicolon:

test = Compile[{}, If[True, 1];];
CompilePrint@test
…………
1     if[ !B0] goto 3
2     goto 3
3     Return

or enclosed by a redundant Do[]:

test = Compile[{}, Do[If[True, 1], {1}]];
CompilePrint@test
…………
1   I1 = I0
2   I3 = I2
3   goto 6
4   if[ !B0] goto 6
5   goto 6
6   if[ ++ I3 < I1] goto 4
7   Return

while a redundant Table[] won't help:

test = Compile[{}, Table[If[True, 1], {1}]];
CompilePrint@test
…………

1   I1 = I0
2   I4 = I3
3   T(R1)0 = Table[ I1]
4   I2 = I3
5   goto 8
6   R1 = MainEvaluate[ Function[{}, If[True, 1]][ ]]
7   Element[ T(R1)0, I4] = R1
8   if[ ++ I2 < I1] goto 6
9   Return

This phenomenon may lead to a total failure of compilation when codes become more complicated:

ie = 200;
ez = ConstantArray[0., {ie + 1}];
hy = ConstantArray[0., {ie}];

f1 = Compile[{{steps}},
Module[{ie = ie, ez = ez, hy = hy},
Do[ez[[2 ;; ie]] = ez[[2 ;; ie]] + (hy[[2 ;; ie]] - hy[[1 ;; ie - 1]]);
ez[[1]] = Sin[n/10];
hy[[1 ;; ie]] = hy[[1 ;; ie]] + (ez[[2 ;; ie + 1]] - ez[[1 ;; ie]]), {n, steps}];
ez]];

f2 = Compile[{{steps, _Integer}, {test, True | False}},
Module[{ie = ie, ez = ez, hy = hy},
Do[ez[[2 ;; ie]] = ez[[2 ;; ie]] + (hy[[2 ;; ie]] - hy[[1 ;; ie - 1]]);
ez[[1]] = Sin[n/10];
hy[[1 ;; ie]] = hy[[1 ;; ie]] + (ez[[2 ;; ie + 1]] - ez[[1 ;; ie]]), {n, steps}];
If[test, ez]]];

f1[1500]; // AbsoluteTiming
{0.0250000, Null}
f2[1500, True]; // AbsoluteTiming

Warnings……

{0.5730000, Null}

So, as the title said, If won't compile when its output is the output of Compile?

Of course it can be easily circumvented, but I wonder if there's a universal rule behind this, or it's just another unreasonable behavior of Compile?

• Identical issue, and solution, to those discussed in this question earlier today. In fact I'd be tempted to close this as a duplicate, except that I think it shows the issue a bit more clearly than the other question. Commented Apr 18, 2014 at 13:26
• @OleksandrR. In fact it's that question that motivate me to ask this one (I've noticed this behavior for some time), I read it but still failed to notice it's an identical issue 囧. Commented Apr 18, 2014 at 13:33

This is a type incompatibility problem. The compiler must make an assignment to the output of If in order to return a value. If[True, 1] is equivalent to If[True, 1, Null], and there is no type that can be assigned to both 1 and Null. You will get the same problem if you make an assignment to the If result when it isn't the final output of Compile:

CompilePrint @ Compile[{}, Block[{x}, x = If[True, 1]]; 2]
I0 = 1
I1 = 2
B0 = True
Result = I1

1 R0 = MainEvaluate[ Function[{}, If[True, 1]][ ]]
2 Return

I'm not sure why you don't get a message, in other cases you do:

CompilePrint @ Compile[{}, If[True, 1, {2, 3}]]

Compile::cif: The types of the two results in If[True,1,{2,3}] are incompatible because their ranks are different. Evaluation will use the uncompiled function. >>

I0 = 1
T(I1)0 = {2, 3}
B0 = True
Result = R0

1 R0 = MainEvaluate[ Function[{}, If[True, 1, {2, 3}]][ ]]
2 Return

Note that if both returns from If are Null there is no problem:

CompilePrint @ Compile[{}, If[True, Null]]
B0 = True
Result = V17

1 if[ !B0] goto 3
2 goto 3
3 Return