# 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]]] Commented Mar 13, 2020 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. Commented Mar 13, 2020 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. Commented Mar 13, 2020 at 23:09
• Fair enough, I'm happy to retract my attempt at commenting Commented Mar 13, 2020 at 23:23
• A bit cumbersome but very robust is this way: Block[{x}, With[{code = x^2 + g[x]}, Compile[{{x, _Real}}, code]]]. Commented Mar 14, 2020 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? Commented Apr 1, 2020 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. Commented Apr 1, 2020 at 18:44
• Ah, I was under the impression that you were a developer. Commented Apr 1, 2020 at 18:49
• @QuantumDot Not of Compile`, no. Commented Apr 1, 2020 at 19:07