Question
· Apr 8, 2019

Can datatype redefine getter/setter?

I have a lot of string properties, which need custom but similar Getters and Setters.

Currently I'm generating Getter and Setter in class generation code but that expands class definition.

Is there a way to specify custom datatype which would generate custom getters and setters?

Discussion (17)0
Log in or sign up to continue

Here's what I've coded.

Property:

Class Test.String Extends %String
{

ClassMethod StorageToLogical(%val As %String) As %String [ CodeMode = objectgenerator ]
{
	set property = $g(%member)
	do %code.WriteLine($c(9) _ "Quit """ _ property _ """")
	quit $$$OK
}

ClassMethod LogicalToStorage(%val As %String) As %String [ CodeMode = objectgenerator ]
{
	set property = $g(%member)
	do %code.WriteLine($c(9) _ "Quit """ _ property _ """")
	quit $$$OK
}

}

Class:

Class Test.Obj Extends %RegisteredObject
{

Property prop As Test.String;

}

However reference to property does not return anything (expected to return property name):

w obj.prop
zw obj.prop
>""

Any ideas?

Turns out it's much easier than I thought:

Class Test.String Extends %String
{

ClassMethod Get() As %String [ CodeMode = objectgenerator ]
{
    do %code.WriteLine($c(9) _ "Quit $g(^Test.String, 0)")
    quit $$$OK
}

ClassMethod Set(%val As %String) As %String [ CodeMode = objectgenerator ]
{
    do %code.WriteLine($c(9) _ "Set ^Test.String = %val")
    quit $$$OK
}

}

Example:

set obj = ##class(Test.Obj).%New()
write obj.prop
>0
set obj.prop=1
write obj.prop
>1

Okay, how do I make this work with methods?

On property get/set I need to call instance method.

I've tried this:

Class Test.String Extends %String
{

Method Get() As %String [ CodeMode = objectgenerator ]
{
    do %code.WriteLine($c(9) _ "Quit ..Test()")
    quit $$$OK
}

}

And class:

/// set obj = ##class(Test.Obj).%New()
/// w obj.prop
Class Test.Obj Extends %RegisteredObject
{

Property prop As Test.String;

Method Test()
{
    quit $random(100)
}

}

But it fails to compile.

NoContext helped. What does it mean?

NoContext
With the same success it is possible to specify NoContext for the class:

Class Test.String Extends %String [ NoContext ]
{

Method Get() As %String CodeMode = objectgenerator ]
{
  %code.WriteLine("  q $this.Test()")
  q $$$OK
}

}
This works too btw:

It doesn't work for me:

MPP5376 : Method or Property 'Test' does not exist in this class.

Sorry,  I had more changes. 
My approach in details

Class DC.String Extends %String  {
ClassMethod Get() As %String [ CodeMode = objectgenerator ]
{    do %code.WriteLine($c(9) _ "Quit $g(^Test.String, 0)")
    quit $$$OK  }
ClassMethod Set(%val As %String) [ CodeMode = objectgenerator ] {
    do %code.WriteLine($c(9) _ "Set ^Test.String = %val")
    do %code.WriteLine($c(9) _ "do zTest()")
    quit $$$OK }

/// this generates Method propTest()
/// but satisfies the Compiler for this class
ClassMethod Test() { quit  ;; from Data definition }
}

compiles this routine:

 ;DC.String.1
 ;(C)InterSystems, generated for class DC.String. Do NOT edit. 10/04/2019 12:00:42PM
 ;;42345370;DC.String
 ;
zGet() public  Quit $g(^Test.String, 0) }
zSet(%val) public Set ^Test.String = %val
      do zTest() }
zTest() public  quit  ;; from Data definition }

and the  using class

Class DC.StringTest Extends %RegisteredObject  {
Property prop As DC.String;
Method Test()
 b   quit ;; from using Class }
}

compiled as 

 ;DC.StringTest.1
 ;(C)InterSystems, generated for class DC.StringTest. Do NOT edit. 10/04/2019 12:02:35PM
 ;;49614632;DC.StringTest
 ;
%NormalizeObject() public {
If '$system.CLS.GetModified() Quit 1
If m%prop Set:i%prop'="" i%prop=(..propNormalize(i%prop))
Quit 1 }
%ValidateObject(force=0,checkserial=1) public {
set sc=1
If '$system.CLS.GetModified() Quit sc
If m%prop Set iv=..prop If iv'="" Set rc=(..propIsValid(iv)) If ('rc) Set sc=$$EmbedErr^%occSystem(sc,rc,5802,"prop",iv)
Quit sc }
zTest() public {
 b   quit ;; from using Class
}
zpropGet() public {
Quit $g(^Test.String, 0) }
zpropSet(%val) public {
Set ^Test.String = %val
do zTest() }
zpropTest() public {
 quit  ;; from Data definition
}

and the test

 SAMPLES>s obj=##class(DC.StringTest).%New()
SAMPLES>set obj.prop=123
 b   quit ;; from using Class
 ^
<BREAK>zTest+1^DC.StringTest.1
SAMPLES 3d1>

Well, the code generator can be tricky.
It's not one of my favorites. But sometimes you have no choice.

OK.
StorageTo../..ToStorage only works in persistent classes where you move content from/to globals.
No chance without storage. 

It doesn't get called in Registered Classes and not when the object wasn't saved.
see my test with %Persistent

set obj=##class(Test.String).%New()
write 
obj.prop    ;nothing loaded yet

set obj.prop=77 write obj.prop   ; unchanged as neither stored nor loaded
77
do obj.%Save(),obj,%Reload() ; force reload to trigger StorageToLogical
write obj.prop  ; and here we go
prop


This proves that there is limited use of the approach.