Leaving aside the wisdom of modifying System functions this is an interesting question.
I would not have been surprised to see this behavior had the input list been packed as I have already learned about low-level optimizations on packed arrays. See:
However that does not appear to be the issue here since (typed in) {1, 2, 3}
is not packed. Apparently the "listable" behavior of Sqrt
is not (only) implemented in terms of the attribute Listable
. As an example here is function without Listable
that still threads over lists:
f[x_List] := f /@ x
f[{1, 2, 3}]
{f[1], f[2], f[3]}
Leonid writes about Listability here:
Quoting:
There are two types of listability - the one in built-in functions,
which pushes threading into the kernel and is fast, and the top-level
one (setting Listable for some functions by the user).
You can not achieve built-in listability by simply setting a
Listable
attribute. The reason is that, while the end result is the
same - automatic threading over lists, the underlying mechanisms to
achieve it are different for built-ins vs user-defined. When a
built-in Listable
function (particularly numerical) is passed lists
as arguments, it dispatches to the special branch which internally
runs the loop, and returns a list of results. So, for a built-in
function, Listable
is rather a signal to pick the internal branch
which deals with lists automatically.
It seems that the absence of Listable
does not prevent this "internal branch" from being used.