I think we may need some more context of what the code looks like and exactly what error message you are getting. We do support $$$CacheError in 2016.1, for example:

Set status=$$$ERROR($$$CacheError,$zerror)

If you are trying to lookup the macro value then use $$$ERRORCODE($$$CacheError), then you can write logic like:

If errorcode=$$$ERRORCODE($$$CacheError) Write "It was a Cache error",!

I fully agree with hoisting constants out of a loop and have recently spent a while optimizing code to use $listnext in SQL and so agree it is a much faster way to iterate over $listbuild structures.

However in your first case of a 'For' loop the end condition is evaluated when entering the loop the first time and is not re-evaluated at all, for example run this:

CACHE20164:USER>set a=2 for i=1:1:a { set a=10 write i,! }
1
2

As you can see it always stops at '2' rather than going on to '10'.

Also there is overhead in converting from a delimited string into a $list format in order to use the more efficient $listnext, you can avoid the O(n^2) overhead with the regular $piece(string,",",i) code in a loop using $find with a starting position and then $extract the item you need. This should perform better than $listnext version of the loop at least for mid sized strings as it avoids the conversion overhead.

The use of ZZW was a mistake and we removed this in the next release after it was introduced.

I did not see any documentation that said that 'ZZ' was reserved for any particular use and the examples in the documentation show functions that do not use 'ZZ' as part of their name so I was trying to avoid user extensions in naming the item 'ZZPRINT' by assuming we can use 'ZZ' and customers will use 'Z<something else>'. I apologize if this caused a problem for you, that was the opposite of my intension.

I would generally advise against using %File class for reading files as this is a very low level wrapper around the COS file commands. For example if you want to apply a translate table you need to know about the 'K' flag on the open command. I much prefer using the %Stream.FileBinary or %Stream.FileCharacter classes as these provide a much more consistent interface to the file.

I fully agree that using the line by line monitor is the way to go, take a look at  %Monitor.System.LineByLine.cls which provides an API to turn this on/off and get information out of the line by line monitoring.

Also for mapping INT lines back to source lines you can look at the API in %Studio.Debugger.cls in method  SourceLine. This class does say it is internal but I think this particular method should be fine to use.