Usually h @@@ {f[1, 2], f[3, 4]} === {h[1, 2], h[3, 4]} but this is not the case when f is Complex: h @@@ {1 + 2I, 3 + 4I } === {1 + 2 I, 3 + 4 I} Since Complexis an atomic and as documentation for Apply states: Applying to atomic objects that do not have subparts effectively does nothing

Using Block to replace Complex with complex gives result as expected for non-atomic case:

Block[{Complex = complex},
List @@@ {Complex[1, 2], Complex[3, 4]}
]
(* {{1, 2}, {3, 4}} *)


But then how come replacing Complex with List while not Apply-ing does not give the same result?

Block[{Complex = List},
{Complex[1, 2], Complex[3, 4]}
]
(* {Complex[1, 2], Complex[3, 4]} *)


As it would have for a non-atomic head:

Block[{f = List},
{f[1, 2], f[3, 4]}
]
(* {{1, 2}, {3, 4}} *)

-
Funnily enough, if I use TracePrint[Block[{Complex = List}, {Complex[1, 2], Complex[3, 4]}]], the replacement happens. Quite odd, this evaluation... – J. M. Jun 19 '13 at 16:19
With[{Complex = List}, {Complex[1, 2], Complex[3, 4]}] works, but still does not explain the behavior. Block[{Complex = complex}, {Complex[1, 2], Complex[3, 4]}] does not work either, so Applying seems to be the key – Ajasja Jun 19 '13 at 16:32
This is a very strange behavior. For example, this works: Block[{Complex}, Complex := List; {Complex[1, 2], Complex[3, 4]}], and after that, the original example works too. Looks like some changes are not propagated properly. – Leonid Shifrin Jun 19 '13 at 16:33
As one might expect, this general technique also doesn't work if the head Complex exists only by implication, as in a packed array. – Oleksandr R. Jun 19 '13 at 16:45
Apparently Complex[1, 2] is not equivalent to 1 + 2I. Block[{Complex = f}, List @@@ {Complex[1, 2], 3 + 4 I}] gives {{1, 2}, 3 + 4I} I thought that was just a syntactic difference – ssch Jun 19 '13 at 18:44

This is hardly a complete answer but I suspect this is the result of special handling of the symbol Complex, much as there is special handling of packed arrays.

Remember that Block only affects things that evaluate, e.g. Block[{a = 1}, Hold[a, b, c]] returns Hold[a, b, c]. I believe that Complex may be passed over when it comes to evaluation. Consider this example outside of Block:

Unprotect[Complex];
Complex = ff;
Complex[1, 2]
Quit[]

1 + 2 I


The head Complex is never evaluated to ff here. Interestingly, with a delayed definition it is:

Unprotect[Complex];
Complex := ff
Complex[1, 2]
Quit[]

ff[1, 2]


I cannot think of a reason within the normal evaluation process for this to be, hence my suspicion of special handling.

-
Try immediate evaluation after you try the delayed one. I also made all these experiments you present here, but somehow I feel that this is not the whole story. – Leonid Shifrin Jun 19 '13 at 16:49
@Leonid Surely this is not the whole story, as stated. Do you agree that there appears to be special handling taking place? – Mr.Wizard Jun 19 '13 at 16:51
I am not sure about it. – Leonid Shifrin Jun 19 '13 at 16:54
It should probably be noted that even Unprotect[Complex]; Complex = hh; Complex -> Complex. Same goes for Integer. – Jacob Akkerboom Jun 19 '13 at 20:33
@JacobAkkerboom This is not so simple. Check this: Unprotect[Complex];Complex := hh;Complexand then Complex =.;Complex = hh;Complex. – Leonid Shifrin Jun 19 '13 at 21:10