Question
· Aug 14, 2023

Generate Method for properties

Hello All,

How do I generate my own method for all properties in my class definition like auto-generated methods PropertyGet(), PropertySet(), PropertyGetStored().

Thanks.

Product version: IRIS 2023.1
$ZV: IRIS for Windows (x86-64) 2023.1
Discussion (14)4
Log in or sign up to continue

Hi Ashok, could you give some more context for what you want to achieve?

If you simply want an instance method that can do something to any property of a persistent class, you could do something like:

Class Package.Data Extends %Persistent
{
    
Property StringProp As %String;
Property IntegerProp As %Integer;

Method TestAnyProp(propName As %String) As %Boolean
{
    if $PROPERTY($THIS, propName) = "" quit 0
    quit 1
}
    
}

But if you specifically want the propSomething format of generated methods, Eduard's solution may be more appropriate.

Worth noting that property accessors like propGet() and propSet() can be overridden.

Hello @Elijah Cotterrell 

Thanks for the suggestion, I need to verify whether the property is modified while saving for opened object and Generally I do some verification with the mentioned piece of code. So, I thought to generate a method like getter and setter method in some cases.

Class Samples.Person Extends %Persistent
{

Property Name As %String;

Property Age As %String;
ClassMethod ValidateObject()
{
    Set obj =##Class(Sample.Person).%OpenId(1)
    w "before: ",obj.PropertyIsModified("Age"),!
    Set obj.Age=12
    Write "after: ",obj.PropertyIsModified("Age"),!
}

Method PropertyIsModified(Property)
{
    Return $Select(Property'="":$Property($THIS,"m%"_Property), 1:0)
}

}

Hello @Joel Solon 

  • The %ValidateObject() method is used to validate the property. Not to find out the property is modified in the opened object
IRISMYDEV>set obj = ##Class(Samples.NewClass2).%OpenId(1)
IRISMYDEV>write obj.Name
Test
IRISMYDEV>zwrite obj.%ValidateObject()
1
IRISMYDEV>set obj.Name="newname"
IRISMYDEV>zwrite obj.%ValidateObject()
1
  • m%_Property is used to verify whether the property is modified before save. Incase If we need to verify

Class Samples.NewClass2 Extends %Persistent
{
Property Name As %String;
Method modified()
{
    write "Property modifed : ",$Property(,"m%Name")
}
}
IRISMYDEV>set obj = ##Class(Samples.NewClass2).%OpenId(1)
IRISMYDEV>do obj.modified()
Property modifed : 0
IRISMYDEV>set obj.Name="test"
IRISMYDEV>do obj.modified()
Property modifed : 1
IRISMYDEV>
  • I hope, we don't have any built in method like "propertyIsModified" to verify the property is modified 

Does this example make it clear? Does this meet your needs?

USER>set human = ##class(Simple.Human).%OpenId(1)

USER>zw human
human=20@Simple.Human  ; <OREF>
+----------------- general information ---------------
|      oref value: 20
|      class name: Simple.Human
|           %%OID: $lb("1","Simple.Human")
| reference count: 2
+----------------- attribute values ------------------
|       %Concurrency = 1  <Set>
|            Company = "GlobaDyne Inc."
|               Name = "Smith,John"
|              Phone = "265-288-5681"
|            Version = 2
+----------------- swizzled references ---------------
|             i%Home = $lb("6489 Clinton Street","Denver","NJ",26882)  <Set>
|             r%Home = ""  <Set>
|             i%Work = $lb("9353 Main Drive","Hialeah","MI",72997)  <Set>
|             r%Work = ""  <Set>
+-----------------------------------------------------

USER>write human.%IsModified()
0
USER>write human.PhoneIsModified()
0
USER>set human.Phone = "111-222-3333"

USER>write human.%IsModified()       
1
USER>write human.PhoneIsModified()   
1
USER>write human.Home.Street
6489 Clinton Street
USER>write human.Home.StreetIsModified()
0
USER>set human.Home.Street = "111 High Street"

USER>write human.Home.StreetIsModified()      
1
USER>

Property methods, or any member methods in general, originate from three places: the property's memberType class, the declared type class (sometimes call the "datatype" class) and the containing class definition.

The memberType is simply the type of class member - property, index, query, method, parameter - all are types of members that can be defined in a class. What isn't well known is that there is a memberType class for several memberTypes. (in the past, this was referred to as the property class) We'll focus on the property memberType here but keep in mind that the concepts extend to indexes, queries, triggers, etc.

There are two categories of property methods. Methods inherited from the datatype class collectively provide the datatype class runtime for the datatype generated specifically for a property. These methods are classmethods but they behave as if they are operating on an instance of the datatype class. That instance is passed as an argument when invoking the method or returned by the method. We think of these methods as running in a provided context.

The second category of property methods is those inherited from the memberType classes. Yes, I wrote classes - plural. That is because in addition to the memberType classes that are automatically inherited by each property, the class definition can specify additional classes as the value of the PropertyClass class keyword. To specify multiple classes simply enclose the list of classes in parentheses.

Class User.Special Extends %RegisteredObject [ PropertyClass = User.MyProperty ]
{

Property MyProperty As %String;
}

In this example, each property defined in User.Special will inherit methods implemented by User.MyProperty. Before we look at User.MyProperty we need to understand another class keyword - NoContext. There is also a NoContext method keyword. When used as a class keyword it applies to all methods that do not also specify NoContext.

The documentation for NoContext describes the code generation implications of using NoContext but does not explain what it means. Perhaps that is because the keyword name implies something other than its compile-time behavior. NoContext simply means that the method has access to the current instance. In other words, the member method does not provide its own context. What member methods do provide their own context? Datatype methods.

Why do we care about context? Simply put, datatype methods should not have the ability to mutate the object since they are intended to implement only the datatype behavior and can access only the provided value.

Class User.MyProperty [ NoContext ]
{

Method IsSpecial() As %Boolean [ CodeMode = generator ]
{
    set ivar = "i%"_$$$QN(%property)
    $$$GENERATE(" return $select(+"_ivar_"#2>0:1,1:0)")
}

}

This is a simple little example of a property method generator. When the Special class is compiled it will as an IsSpecial property method to each property defined by the class.

MyPropertyIsSpecial() methodimpl {
 return $select(+i%MyProperty#2>0:1,1:0)
}

And when you instantiate Special you can invoke this method.

USER>set special = ##class(Special).%New()

USER>set special.MyProperty = "200"

USER>write special.MyPropertyIsSpecial()
0
USER>set special.MyProperty = 201

USER>write special.MyPropertyIsSpecial()
1