Question
· Dec 10, 2021

Is it possible to change the code of a class programmatically?

Hi folks!

I'm curious if it is possible to change the class method to another class?

I call a method of a system class  to generate another class. But there is a bug/feature in a library class, so I need to tweak a bit the generated method, e.g. add additional parameter and change the line to "if" the parameter.

I hope to do this programmatically after class generation and change the code in a way I like.

What are the options?

Product version: IRIS 2021.1
Discussion (7)1
Log in or sign up to continue

Sure!  very condensed

  • set cls=##class(%Dictionary.ClassDefinition).%OpenId("<pkg>.<classname>")
  • set met=cls.Methods.GetAt(1)  ; may need some search
  • set imp=met.Implementation   ; a GlobalChar.Stream
  • write imp,OutputToDevice()

or you jump to the Method directly

  • set met=##class(%Dictionary.MethodDefinition).%OpenId("<pkg>.<classname>||<methodname>")

And these classes have tons of params to set or clear by specific methods

Open the ClassDefinition: Set ClassDef=##class(%Dictionalry.ClassDefinition).%OpenId(ClassName)
Add the Parameter

Set Parm=##class(%Dictionary.ParameterDefinition).%New(ClassName_":"_ParameterName)
Set Parm.Default=ParameterValue
Do ClassDef.Parameters.Insert(Parm)


Find the desired method in ClassDef.Methods collection by MethDef.Name
Use the MethDef.Implementation stream to manipulate the code
Compile the class.

Yeah, of course, you can change any class, if it's not a system and not deployed class stored in a read-only database

looks like you already know how to generate classes, so, to edit some method, you have to open a particular method by its id, which can be constructed from the class name and the method name.

USER>set method = ##class(%Dictionary.MethodDefinition).%OpenId("%Library.File||Exists") 

USER>write method.Implementation.Size
56

Thanks @Dmitry Maslennikov, @Robert C. Cemper and @Herman Slagman !

Turn out it's not that hard with your help!

The result can be observed here - adding a parameter and the implementation to a method in csvgen.

And yes, here is the code itself:

ClassMethod AddAppendtoImport(pClassName As %String) As %Status
{
 
    set method = ##class(%Dictionary.MethodDefinition).%OpenId(pClassName_"||Import")

    if method.FormalSpec["pAppend" quit $$$OK
    set method.FormalSpec=method.FormalSpec_",pAppend:%Boolean=0"
    set imp=method.Implementation
    set newImp=##class(%Stream.TmpCharacter).%New()

    while 'imp.AtEnd {
        set line=imp.ReadLine() 
        if line'["%DeleteExtent" {do newImp.WriteLine(line)}
        else {
            do newImp.WriteLine($p(line,"do")_"if 'pAppend do ..%DeleteExtent(,.tDeleted,.tInstances,1)")
        }
        }
    set method.Implementation=newImp
    set sc=method.%Save() 
    if $$$ISERR(sc) return sc
    set sc=$System.OBJ.Compile(pClassName,"cuk")
    return sc
}