There is often a question as to why newlines aren't doing what the user expects inside Vim script.

When \n is stored in a Vim variable/register/etc, it is stored as a NULL, and then translated back to a real newline under circumstances such as "put".

Try inserting a newline in insert mode, i.e. ^V^J (or ^Q^J if you're using the mswin behavior). You will see a <00> show up.

Now try these to help understand further:

let @a = "a" . "\n" . "b"
or
let @a = "a" . "\x0a" . "b"

and put it into the buffer using "ap or :put a

You should see:

a
b

"put" is especially smart about translating the newlines from NULLs back to 0x0a. Now do:

call setline(".", @a)
or
call append("$", @a)

You should see:

a<00>b

It's not a happy reality, since NULLs and newlines cannot cooexist in Vim script strings in various circumstances.

In Vim 7 you have the option of giving a list to setline() and append(), which solves the line break ambiguity:

call setline(".", [ 'a', 'b' ] )

I'm now using lists everywhere I can, in preference to concatenated strings with newline separators. I usually split() any such strings I find into a list for easier manipulation. This sidesteps all the usual pitfalls trying to handle line breaks manually as embedded characters.

You can see that Vim is still storing the carriage return, but is getting translated on the back end, in this case by the s/\r/\r/ command. I think the \r case is treated specially by the Ex s/ command, since :put a doesn't put 'a' and 'b' on different lines.

The moral of the story is: find out what works, and remember it, because trying to apply universal rules won't work.