Written by

Senior Software Engineer
Question Ashok Kumar T · 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

Comments

Eduard Lebedyuk · Aug 14, 2023

You need your own datatype, which implements method generators for Set, GetStored etc.

After that use your own datatype in your main class. Example.

0
Ashok Kumar T  Aug 14, 2023 to Eduard Lebedyuk

Hello @Eduard Lebedyuk 
Thanks for the samples.Creating my own datatype and implementation is works for me.

0
Elijah Cotterrell · Aug 14, 2023

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) = ""quit0quit1
}
    
}

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.

0
Ashok Kumar T  Aug 15, 2023 to Elijah Cotterrell

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=12Write"after: ",obj.PropertyIsModified("Age"),!
}

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

}
0
Joel Solon  Aug 23, 2023 to Ashok Kumar T

I think it would be great if you would explain the use case to the community.

  • Why do you need to do your own property-by-property validation separate from %ValidateObject()
  • Why are you using "m%"_Property and not just Property?
  • Why can't you use the built-in propertyIsModified() method to verify if a property is modified?
0
Ashok Kumar T  Aug 23, 2023 to Joel Solon

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 
0
Joel Solon  Aug 24, 2023 to Ashok Kumar T

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>
0
Ashok Kumar T  Aug 24, 2023 to Joel Solon

Exactly. Thanks for the samples. This will helps to figure out the property is modified or not. 

0
Ben Spead  Aug 28, 2023 to Joel Solon

Great samples Joel and right to the point! (as usual ;) )

0
Dan Pasco · Aug 26, 2023

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
0
Ashok Kumar T  Aug 28, 2023 to Dan Pasco

Thank you @Daniel.Pasco. It's a wonderful detailed clarification for the property and member type class

0
Ben Spead  Aug 28, 2023 to Dan Pasco

@Dan Pasco - anytime I see you respond to a D.C. question I always take the time to read it carefully as I know I will definitely learn something (and this response did not disappoint!)  Quick question - what is the use of $$$QN() as I can't find it in the docs?

I think you should consider publishing this as a standalone article.

0
Dan Pasco  Aug 28, 2023 to Ben Spead

$$$QN is a macro that we use in code generators to delimit identifiers. It returns either the parameter value unaltered or the quoted parameter. For example, if you have a property named select then it has to be delimited for use in SQL since it is a reserved word. $$$QN("case") returns "case".

0
Ben Spead  Aug 28, 2023 to Dan Pasco

Thanks Dan - it looks like that would be incredibly useful :)

0