There is a common belief, as you mention in your article, that dynamic sql does not have compile plans. This is not true.
Any adhoc query i.e not an SP, is parameterised, compiled and put in the cache. Depending on the complexity of the query (sub tree cost) the query will stay in the cache until it is booted out because of another query.
the main issue is with parameterisation, it doesn't really work. It is supposed to convert values into parameters so that when you call the same query with another value you can get the same plan.
i.e select * from mytable where col1 = 1
and select * from mytable where col1 = 2
should result in the same parameterised query
select * from mytable where col1 = @p1
Because this doesn't work you should use sp_executesql and do the parameterisation yourself
i.e the above becomes
sp_executesql N'select * from mytable where col1 = @p1', N'@p1 int', 1
So if you use sp_executesql the performance will be the same as an SP, (except adhoc queries are booted out the cache before SPs).
Articles to read on this are
This is detailed in depth somewhere but I can't find it at the moment.
Co-author of SQL Server 2000 XML Distilled