# NIntegrate evaluates its 1st argument while it has the attribute HoldAll?

NIntegrate owns the attribute HoldAll:

Attributes@NIntegrate
(* {HoldAll, Protected} *)


However, when reading this answer, I surprisingly noticed that at least in the following case the 1st argument of NIntegrate is actually evaluated!:

NIntegrate[BesselJ[9/2, x], {x, 1, 2}] // Trace


So my question is, does NIntegrate always evaluates its 1st argument? If the answer is Yes, what's the meaning of this design, why not simply use HoldRest?

• Another example: NIntegrate[LegendreP[9, x], {x, 0, 1}] // Trace. I don't have time to write a detailed answer at the moment, but as I noted, the IntegrationMonitor framework might be revealing (maybe Anton will write an answer if he sees this). Commented Jun 9, 2016 at 6:21
• @J.M. After some more testing, I found the phenomenon seems to be quite general, a not-that-outstanding but simpler example: NIntegrate[x + x, {x, 0, 1}] // Trace. Commented Jun 9, 2016 at 6:33

Actually the observed behavior is in full accord with the HoldAll attribute, just check what happens when there is no such attribute:

nIntegrate[x + x, {x, 1, 2}] // Trace

{{x + x, 2 x}, nIntegrate[2 x, {x, 1, 2}]}


From the above it is seen that the arguments are evaluated before applying the rules associated with the function nIntegrate. The purpose of the HoldAll attribute is to prevent evaluation of the arguments before applying the rules, and this is exactly what happens in the case of NIntegrate:

NIntegrate[x + x, {x, 1, 2}] // Trace

{NIntegrate[x + x, {x, 1, 2}], {x + x,
2 x}, {{x} =., {x =.}, {x =., Null}, {Null}}, {x =., Null}, 3.}

• I think now I understand the meaning of this design, if NIntegrate just owns HoldRest, something like x = 0; NIntegrate[x + x, {x, 1, 2}] won't give the desired result, but then another question comes to my mind: why *Plot/*Plot3D isn't designed to be like this? If so, there won't be any "Why Plot[D[x, x], {x, 0, 1}] doesn't work?" question!… well, maybe I should once again start a new question? Commented Jun 10, 2016 at 4:47
• @xzczd Actually Plot and Plot3D also work the same way: they do have the HoldAll attribute but in version 10 somehow it is not listed when you evaluate Plot // Attributes (in previous versions it was listed). You can receive direct evidence that the attribute does work by evaluating Trace[Plot[x + x, {x, 0, 2}]][[;; 2]]. As to "Why Plot[D[x, x], {x, 0, 1}] doesn't work?", it is easy to understand it you remember that Plot localizes variables like Block (read the first point under the "Details and Options" section!). So with Block[{x = 1}, D[x, x]] you get exactly the same! Commented Jun 10, 2016 at 6:26
• No, they're not same, as mentioned by Marius Ladegård Meyer in the answer above: "NIntegrate first localizes the values of all variables, then evaluates f with the variables being symbolic, and then repeatedly evaluates the result numerically." If *Plot/*Plot3D works like this, then D[x, x] will become 1 before the numeric value is plugged in. Commented Jun 10, 2016 at 7:19
• @xzczd Yes, but these details aren't from the HoldAll attribute: it is internal working of these functions. Actually Plot also evaluates f with variables being symbolic as you can see from f[x_Symbol] := Print["symbolic evaluation!"]; f[x_Real] := x; Plot[f[x], {x, 0, 1}];. Commented Jun 10, 2016 at 7:32
• @xzczd You can force Plot to work like NIntegrate using undocumented option Evaluated -> True: Plot[D[x, x], {x, 0, 1}, Evaluated -> True]. Commented Jun 10, 2016 at 7:36

From the "Details and Options" section in the docs:

NIntegrate first localizes the values of all variables, then evaluates f with the variables being symbolic, and then repeatedly evaluates the result numerically.

So I guess this is expected behavior.

• Oh, I should have checked the document more carefully! Commented Jun 10, 2016 at 4:44