# Why changing list's head takes time?

Consider

AbsoluteTiming[Range[10^7];][[1]]


0.035000

and

AbsoluteTiming[HoldComplete @@ Range[10^7];][[1]]


0.725000

Why it takes twenty times longer to change head than to create a list? Since HoldComplete doesn't evaluate arguments one would think that head changing should be fast.

-
Because HoldComplete unpacks, when Apply is used (or, rather, Apply unpacks). –  Leonid Shifrin May 25 '13 at 11:14
@Leonid Shifrin no preamble, but clearly answer material. –  Yves Klett May 25 '13 at 16:10
@YvesKlett All right, I followed your suggestion. –  Leonid Shifrin May 25 '13 at 17:26

In your example, you originally crate a packed array. If you read about packed arrays in the answers in the linked question, in documentation or elsewhere, you will see that these are special objects, lower-level than general Mathematica lists / expressions.

Because of this, not all Mathematica operations preserve these objects. Those which don't are said to unpack. Some considerations regarding (avoiding) unpacking can be found here. In particular, it was mentioned and illustrated there that Apply necessarily unpacks. This is just because of its nature: it replaces the current head of an expression with a different head.

It is easy to check whether or not unpacking happens - use On["Packing"]:

On["Packing"]

HoldComplete @@ Range[10]


During evaluation of In[125]:= DeveloperFromPackedArray::punpack1: Unpacking array with dimensions {10}. >>

(*  HoldComplete[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]  *)

Off["Packing"]


Unpacking is a process of replacing a packed array with its unpacked, higher-level equivalent generic Mathematica list. For large arrays, this can take quite some time, which is what you observed. This has nothing to do with HoldComplete, because unpacking happens slightly earlier, and has nothing to do directly with the top-level evaluation - which is the only evaluation that HoldComplete may affect. Unpacking is a lower-level action.

-
Setting the 0th Part to something other than List also unpacks. So, although it's true that Apply does unpack, I think the reason is that packed arrays can only have head List, rather than that this is due to Apply itself. –  Oleksandr R. May 25 '13 at 19:26
@OleksandrR. Sure, I implied this. Perhaps, I could have articulated this point better, thanks. –  Leonid Shifrin May 25 '13 at 20:00
@LeonidShifrin - I remember reading in the docs that Range[] had some sort of special internal representation, but don't recall it was ever explained beyond that. Makes me wonder about how best to use this function (so as to avoid the problem OP stumbled into). Interesting. –  telefunkenvf14 May 30 '13 at 4:47
@telefunkenvf14 It's not just about Range` - all packed arrays are like that. You can think of them as an internal (lower-level) data type on which all relevant Mathematica's built-in functions have been overloaded. Some of the suggestions how to use them effectively you can find in the links I gave in the answer. –  Leonid Shifrin May 30 '13 at 10:29
@LeonidShifrin - I've read lots of stuff you and others have written on the interaction between packed and regular objects, and potential for unexpected performance losses caused by unpacking. I guess what I was trying to convey was mild surprise that Range[] itself is represented as a packed array. Again, the docs mention range being 'special' but I've never come across any other details. Another reason this surprised me a bit is that Range[1,800], when evaluated alone, doesn't return as PackedArray[Integer, <800>]. I didn't think packed arrays automatically unpacked like that (in isolation). –  telefunkenvf14 May 30 '13 at 21:44