# Compiling a function depending on an external function

Consider the simple case:

g[x] := x^3;
f[x] := x^2 + g[x];
cf = Compile[{{x, _Real}}, x^2 + g[x]]


Evaluating the two functions, Mathematica complains that the second depends on the function g[x], saying:

CompiledFunction::cfex: Could not complete external evaluation at instruction 2; proceeding with uncompiled evaluation.

Which is the correct way to compile the function f in this case?

• Compile[{{x, _Real}}, Evaluate[x^2 + g[x]]] Mar 13 '20 at 17:30
• I get no error in V12 from g[x_] := x^3; cf = Compile[{{x, _Real}}, x^2 + g[x]], although it and @ilian's suggestion both contain MainEvaluate[]. Note the argument to g is a pattern x_, not a symbol x. Mar 13 '20 at 21:45
• @ilian I wouldn't do that, without at least wrapping a Block[{x}, ...] around Compile. But even then, I think it is generally an error - prone practice, unless you are in full control of exact evaluation path for the stuff inside Evaluate. Mar 13 '20 at 23:09
• Fair enough, I'm happy to retract my attempt at commenting Mar 13 '20 at 23:23
• A bit cumbersome but very robust is this way: Block[{x}, With[{code = x^2 + g[x]}, Compile[{{x, _Real}}, code]]]. Mar 14 '20 at 7:44

Long time ago I wrote a macro, which expands global DownValues - based definitions, called withGlobalFunctions. It can be found at the end of this post. With it, all you need to do is wrap the Compile call like this:

g[x] := x^3;
f[x] := x^2 + g[x];
cf = withGlobalFunctions @ Compile[{{x, _Real}}, f[x]]


This has the advantage over Evaluate advice in that you can't leak a global value for x in, even if it exists. And it has an advantage over "InlineExternalDefinitions" -> True advice in that it expands arbitrary long chains of calls.

The limitation of this approach is that patterns in function definitions you may want to inline / expand in this way, better be very simple, involving blanks but not much else. This is because what this does is a kind of a macro-expansion, without actual evaluation involved. So that expansion will get stuck if patterns do any non-trivial checks.

withGlobalFunctions can trivially be extended to expand definitions based on other ...Values. As written, it only expands definitions from Global context, but that restriction can be removed or lifted as well.

• So what good is "InlineExternalDefinitions->True" when withGlobalFunctions is superior in every way? Why can't "InlineExternalDefinitions->True" simply call withGlobalFunctions? Apr 1 '20 at 18:30
• @QuantumDot I don't know. "InlineExternalDefinitions" is a built-in option. Perhaps the developers wanted to play it safe, and limit it in scope. As to your last question, it is largely rhetorical, since withGlobalFunctions is not a built-in. OTOH, anyone is free to define their own wrapper around Compile, which could do that. Apr 1 '20 at 18:44
• Ah, I was under the impression that you were a developer. Apr 1 '20 at 18:49
• @QuantumDot Not of Compile`, no. Apr 1 '20 at 19:07