A very interesting question. I decided to write a singleton, with the idea that it searches process memory for other instances of this class and returns existing OREF if found. It also stores data in global and retrives it from there on a first load:

/// Singleton pattern implementation
Class Utils.Singleton Extends %Library.SystemBase
{

/// Global to store content
Parameter Global = "^Singleton";

/// Actual object content
/// It can be be anything: string or a dynamic object
Property Content As %String;

/// This method finds OREF for an object of a current class if it exists in a current process
ClassMethod GetOref() As %Integer
{
    // Get current classname
    Set Cls = $ClassName()
    Set OREF = $$$NULLOREF
    
    // This query returns a list of all object instances currently in memory within the current process.
    &sql(SELECT Count(OREF),OREF INTO :Count,:OREFTemp FROM %SYSTEM.OBJ_ObjectList() WHERE ClassName=:Cls)
    
    If Count'=0 {    
        Set OREF = OREFTemp
    }
    Return OREF
}

/// If no object of this class is found in process memory
/// then a new one would be returned
/// with Content value taken from global
///
/// If there is an object of this class in memory
/// then it would be returned
ClassMethod Get() As Utils.Singleton
{
    Set OREF = ..GetOref()
    If OREF = $$$NULLOREF {
        Set Obj = ..%New()
    } Else {
        // Convert integer-oref into real OREF
        Set Obj = $$$objIntToOref(OREF)
    }
    Return Obj
}

/// Test singleton object
/// Do ##class(Utils.Singleton).Test()
ClassMethod Test()
{
    Set a = ##class(Utils.Singleton).Get()
    Set a.Content = $Random(100)
    Set b = ##class(Utils.Singleton).Get()
    Write "object b: " _ b.Content,!
    Do a.Save()
    Kill
    Set c = ##class(Utils.Singleton).Get()
    Write "object c: " _ c.Content
}

/// Constructor, loads data from global
Method %OnNew() As %Status
{
    // Return:($Stack($Stack-2,"PLACE")'["Get") $$$ERROR($$$GeneralError, "Сall Get method")
    Set ..Content = $Get(@..#Global)
    Return $$$OK
}

/// Saves data to global
Method Save()
{
    Set @..#Global = ..Content
}

}

Run:

Do ##class(Utils.Singleton).Test()

I tried to disable direct instantiation with $Stack checking, but it seems to fail from a terminal. I think it would work from non-interactive code, but I had not checked. Another way would be to set some variable in Get method and check it from %OnNew() method.

Download xml from GitHub.

Sure. To see deprecated classes for some version execute this query against it:

SELECT ID, Description FROM %Dictionary.ClassDefinition WHERE LOWER(Description) [ 'deprecated'

To see deprecated methods execute this query:

SELECT parent AS "Class", Name AS "Method", Description 
FROM %Dictionary.MethodDefinition 
WHERE LOWER(Description) [ 'deprecated'

And to see deprecated properties execute this query:

SELECT parent AS "Class", Name AS "Method", Description
FROM %Dictionary.PropertyDefinition 
WHERE LOWER(Description) [ 'deprecated'

Note, that this queries only return classes/methods/properties which contain "deprecated" in their definition. To catch deprecated inherited classes/methods/properties query %Dictionary.CompiledClass/%Dictionary.CompiledMethod/%Dictionary.CompiledProperty instead.

Consider adding links to cache documentation from the page that describes the issue, we now have version agnostic urls even. For example this issue could use a link to documentation.

 

Another question is: what's wrong with postconditionals? They exist not only in caché objectscript and in fact very useful as they allow elimination of all 3 lines blocks with one if condition and one action to execute if if is true. Can I disable an issue type for a project?

Sure. You could use %CELLZERO instead:

WITH  MEMBER [MEASURES].[Revenue as Percent of Total] AS 'Measures.[Amount Sold] / %MDX("select Measures.[Amount sold] on 1 
from holefoods","%CONTEXT","filters|columns")',FORMAT_STRING='##.##%;;;;' 
MEMBER [MEASURES].[Revenue Percent Cumulative] AS 'Measures.[Revenue as Percent of Total] + %CELLZERO(0,-1)',
FORMAT_STRING='##.##%;;;;' SELECT {[Measures].[Amount Sold],[MEASURES].[REVENUE PERCENT CUMULATIVE]} ON 0,
NON EMPTY ORDER([Product].[P1].[Product Category].Members,Measures.[Amount Sold],BDESC) ON 1 FROM [HoleFoods] 

Jokes aside, why do you  need to remove %CELL usage?

Formatted your code a little.

getst(getvars, StBeg, temp) ; Save call stack in local or global array
 ; In:
 ; getvars = 1 - save variables defined at the last stack level
 ; getvars = 0 or omitted - don't save; default = 0
 ; StBeg - starting stack level for save; default: 1
 ; temp - where to save ($name).
 ; Out:
 ; temp - number of stack levels saved 
 ; temp(1) - call at StBeg level
 ; temp(2) - call at StBeg+1 level
 ; ...
 ; temp(temp) - call at StBeg+temp-1 level
 ;
 ; Calls are saved in format:
 ; label+offset^rouname +CommandNumberInsideCodeLine~CodeLine w/o leading spaces"
 ; E.g.:
 ; temp(3) = First+2^%ZUtil +3~i x=""1stAarg"" s x=x+1 s c=$$Null(x,y)"
 ; Sample calls:
 ; d getst^%ZUtil(0,1,$name(temp)) ; save calls w/o variables in temp starting from level 1
 ; d getst^%ZUtil(1,4,$name(^zerr($i(^zerr)))) ; save calls with variables in ^zerr starting from level 4
    new loop,zzz,StEnd
    set getvars = $get(getvars)
    set StBeg = $get(StBeg, 1) 
    kill @temp 
    set @temp = 0 
    set StEnd = $STACK(-1)-2
    for loop = StBeg:1:StEnd {
        set @temp = @temp+1
        set @temp@(@temp) = $STACK(loop, "PLACE") _ "~" _ $zstrip($STACK(loop, "MCODE"), "<W") 
        if getvars,(loop=StEnd) {
            set zzz="" 
            for { 
                set zzz = $order(@zzz)
                quit:zzz=""  
                set @temp@(@temp,zzz) = $get(@zzz)
            }
            if $zerror'="" {
                set @temp@(@temp,"$ze") = $zerror
            }
         }
    }
     quit 1