Why Function is not identical to & in autocompilation?

Here is the example, copied from here

square = Function[x, x^2];
square1 = #^2 &;


the timing and unpacking status shows

data = RandomReal[{0, 10}, {10000}];

AbsoluteTiming[DeveloperPackedArrayQ[Map[square, data]]]
AbsoluteTiming[DeveloperPackedArrayQ[tmp1 = Map[square1, data]]]

{0.000771589, True}
{0.000748647, True}


Now we add external variable into these two definition.

a = 1
square = Function[x, x^2 + a];
square1 = #^2 + a &;


and time it again, you got

{0.0336384, False}
{0.0062035, True}


we can see & is still autocompiled, while Function is not. Why? I think the documentation treats them as identical way of writing. This distinction is oddly subtle, I just found it today. What is bad is that without Function, we can not give parameters names, thus less readability.

• To be precise, it seems that square = Function[x, x^2 + a]; isn't compared in Map. I think this can be considered as another evidence that the auto-compilation of pure function is still not that stable currently. – xzczd Dec 3 '16 at 6:27
• It's not just about autocompilation. square is slower than square1 without compilation. You can use Trace to see that there is a significant difference in the evaluation. Autocompilation can be switched of with SetSystemOptions["CompileOptions" -> {"MapCompileLength" -> \[Infinity]}] and increases the difference in your second case, while it removes the difference in your first case. – Karsten 7. Dec 3 '16 at 7:22
• Hi, @Karsten7. I think it is might not be the point. The goal to use Function is to make use of autocompilation. When & and Function both been autocompiled, they are of same speed. If speed is not of concern, then I can just use square2[x_] := x^2;, and in case of "MapCompileLength" -> \[Infinity], square2[x_] := x^2 is actually faster than Function. – matheorem Dec 3 '16 at 7:47
• square2 = With[{a = a}, Function[x, x^2 + a]] would autocompile properly. Maybe "InlineExternalDefinitions" is handled differently? – Karsten 7. Dec 3 '16 at 7:50
• SetSystemOptions[ "CompileOptions" -> {"CompileReportFailure" -> True, "InternalCompileMessages" -> True}] can be used to switch on the generation of an error message. – Karsten 7. Dec 3 '16 at 7:51

The solution, as suggested by Karsten7, in a comment is to use With.

data = RandomReal[{0, 10}, {10000}];

a = 1;
With[{a = a}, square = Function[x, x^2 + a]];
square1 = #^2 + a &

Timing[DeveloperPackedArrayQ[Map[square, data]]]
Timing[DeveloperPackedArrayQ[tmp1 = Map[square1, data]]]


{0.000578, True}

{0.000528, True}

• The question asks why, perhaps we could elucidate the underlying reason. – M.R. Jan 10 '17 at 3:07