OK :) But how to use this variable name generator? :)

 set myNewVarName = ..GetNewVarName() // oops, no
 set @..GetNewVarName() = "" // now it's OK, but I need to call this function once more
 set @..GetNewVarName() = $ORDER(@@..GetNewVarName()) // oops, another variable names

Things get complicated here. I think we can stop on the solutions Michael and Timothy proposed.

Thanks!

Thank you, Timothy! This is good, but what if user specify ^||VariableNameList process-private variable before calling the method? The value will be lost:

USER>set ^||VariableNameList = "TempVal" zwrite ##class(Test.Class).GetVariablesByTimothy()
$lb("Einstein","Mozart")
USER>write ^||VariableNameList
...TempVal is now gone!...

Maybe there is no absolutely save method to get the variables list without touching/rewriting other variables or globals. I hope it is enough just to name temporary variables as no one suggests to name.

This is awesome. It works! Wondering how many things COS has.

But it also outputs variable x. I wrapped your code into the method, and that's what I got:

ClassMethod GetVariables() As %List
{
  set UndefinedSpecialList = $LB()
  set UndefinedSpecialInt = 0
  set Undefined = ""
  set Undefined = $ORDER(@Undefined)
  while (Undefined '= "") {
    quit:($ORDER(@Undefined) = "UndefinedSpecialList")
    set $LIST(UndefinedSpecialList, $INCREMENT(UndefinedSpecialInt)) = Undefined
    set Undefined = $ORDER(@Undefined)
  }
  return UndefinedSpecialList
}

It works awesome until user specify variables named UndefinedSpecialList, UndefinedSpecialInt and Undefined. I suppose user won't ever name variables this way, of course, but the method which will consider this is the winner.

Thanks, Dmitry, this is very close to what can be true. But to use this I need to interrupt WaitMsg method and check if the global exists each... Second? The one idea I come up with is to set timeout for that: set st = $system.Event.WaitMsg(, 1) if $LG(st,1)=0 {/*check if the process is gone and wait again*/} else {/*handle message*/} but is this the best way to do it? Are there any sort of registering trigger or system "interrupt" for this?

Jobbed process runs independently of parent process.
Killing a  parent does not kill its children.

Oops. Thank you, it does not kill children process really.

In my application two processes already use interprocess communication. Child process rely on $ZPARENT variable. Is it possible to change it? Or the only way is to use custom variable to hold the parent's process ID?

Thanks John, the above terminal transcript is not correct showing what I wanted to show. I've fixed this.

Why can't you understand the purpose of this?

I can only transfer strings by some channel (f.e. interprocess communication). Now I need to send the array of strings (list, object, etc) from sender to receiver. To send this array, I must convert it to the string and then, after receiving, convert it back to array to read it's elements. How to do this in Caché 2013.*? The strings in array can contain any characters, so it is not possible to specify any delimiter character.

Finally I got why the question is pretty confusing for you. Just imagine, I didn't know that $lb() returns the simple string. I didn't know that I can write this string to file, read it from file, and then apply $LISTGET function to it. I didn't know $LISTGET function takes string type. I thought that $LIST is something more than just a string.

So the solution:

set string = $LB(1,2,3,",",5)
/* send this string anywhere */
set element = $LISTGET(string, 4) // = ","

[UPD fixed] Got you. Incredible! It seems that this is what I needed:

USER>set string = $lb($C(1),$c(2),$c(3),",",$c(0))
USER>w $a($LISTGET(a,1))
1
USER>w $a($LISTGET(a,2))
2
USER>w $a($LISTGET(a,3))
3
USER>w $LISTGET(a,4)
,
USER>w $a($LISTGET(a,5))
0

Until the list values may contain any set of characters here this is the best solution, thank you, Jon!

Thank you, Evgeny!

Showing the logs has a lot of use cases, but the most common of the top of my head are:

  1. To notify user that no errors occurred during installation and to help track any errors if any happened;
  2. To show the user what happened and what was configured;
  3. And even to collect installations statistics and catch any unpredictable error logs during setup, as I do in my VisualEditor project.

Daniel, 

Also, in many cases, when you compile a class, you only want to perform changes only once, not with every compilation.

This can be easily held in the case of Projections. For example, by testing whether the compiled installer exists in the system, or, as I do in my project, by checking if the project's global exists, whatever. The only thing you need to write all of this pure COS code to perform the checks and build the whole installation logic.

Not sure if %Installer gives more control, except of the moment when you trigger the installation process. It looks for me as a kind of framework with a lot of useful things.

The ideal variant here would be to trigger %Installer's setup from CreateProjection method I think.