Is it safe to use properties in a where clause ?

Posted by cverbiest on 10-Feb-2016 06:54

Is it save to use properties instead of variables in a where clause ?

My tests show that it works but there may be drawbacks I haven't though about.

I did some performance tests and the results are similar

1156 ms for 100000 finds with variable

1194 ms for 100000 finds with property

Posted by Simon L. Prinsloo on 10-Feb-2016 07:37

Look at the call stack in the debugger (or PROGRAM-NAME(1) in a getter or setter).

I came to the conclusion that there is no difference between a property without a getter/setter and a regular variable.

On the other hand, if there is a getter, the compiler create a "propGet_<PROPERTYNAME>" method returning the same type as the property's data type and if there is a setter, the compiler creates a void "propSet_<propertyname>" method, taking the input parameters that you specified in the setter.

So if there is a getter, references that reads the property essentially gets replaced with a method call to the getter, unless you are already in the getter. If there is a setter, assignments are effectively converted into method calls to the setter, unless you are already in the setter.

More testing, especially when we could not WAIT-FOR in functions, brought me to the conclusion that VOID METHODS seems to be compiling to constructs that are the same as, or very close to, internal procedures, while non-VOID methods compiles to construct that are the same as or similar to user defined functions.

With regard to properties, setters would follow the same rules and have the same restrictions that you would experience with VOID methods and/or internal procedures, while getters would impose the same restrictions as FUNCTIONS and non-VOID methods (e.g. cannot be referenced after an indexed field in an ASSIGN statement and could not halt for user input in older versions ).

In other words, in your case, properties with no getter block can be used like variables, but those with a GET(): END GET. must be treated as METHOD/FUNCTION calls.

The problem is that you may not know if I have implemented a GETTER, or I may implement one later on and have an adverse effect on your code. In principle, if I suspect that these might be code, especially potentially expensive or slow code, behind a property, I will normally put it in a local variable if I am going to reference is more than once.

There are cases where I intentionally write the code so that I can always reference it directly and calculate the value only once when needed, but that requires that you keep the value in a private variable and maintain a flag to indicate if you need to (re-)calculate. You also need to reset this flag for any and all of these properties whenever anything that may have an effect on them changes, which immediately opens the door for human error.

Posted by Peter Judge on 10-Feb-2016 08:08

Do you expect the value returned by the property to change between iterations? If so, you will run into problems since the WHERE only evaluates once.
 
The test code below only displays one message in each case.
 
def temp-table tt1 no-undo
    field f1 as dec
    field f2 as char.
   
def var i as int.  
def var o as PropGet.
 
do i = 1 to 100:
    create tt1.
    f1 = i.
    f2 = string(i).
end.
 
o = new PropGet().
o:GetterProp = 1.0.
o:NekkidProp = 1.0.
 
for each tt1 where tt1.f1 = o:GetterProp:           
    o:GetterProp= tt1.f1 + 1.
                
    message
    'tt1:' tt1.f1 tt1.f2 skip
    'GetterProp' o:GetterProp skip
    'can-find?' can-find(first tt1 where tt1.f1 = o:GetterProp)
    view-as alert-box.    
end.
 
message 'done GetterProp'
        view-as alert-box
 
for each tt1 where tt1.f1 = o:NekkidProp:           
    o:NekkidProp = tt1.f1 + 1.
                
    message
    'tt1:' tt1.f1 tt1.f2 skip
    'o:NekkidProp' o:NekkidProp skip
    'can-find?' can-find(first tt1 where tt1.f1 = o:NekkidProp)
    view-as alert-box.    
end.
message 'done NekkidProp'
        view-as alert-box
 
And the PropGet class too
class PropGet:
    define public property GetterProp as dec no-undo
    get():
        return exp(GetterProp, 2).
    end get.
    set.
 
    define public property NekkidProp as dec no-undo get. set.
       
end class.
 
 

All Replies

Posted by Marian Edu on 10-Feb-2016 07:02

my guess is will work till you add a getter for the property... don't remember exactly if was already bitten though :)

Posted by Simon L. Prinsloo on 10-Feb-2016 07:37

Look at the call stack in the debugger (or PROGRAM-NAME(1) in a getter or setter).

I came to the conclusion that there is no difference between a property without a getter/setter and a regular variable.

On the other hand, if there is a getter, the compiler create a "propGet_<PROPERTYNAME>" method returning the same type as the property's data type and if there is a setter, the compiler creates a void "propSet_<propertyname>" method, taking the input parameters that you specified in the setter.

So if there is a getter, references that reads the property essentially gets replaced with a method call to the getter, unless you are already in the getter. If there is a setter, assignments are effectively converted into method calls to the setter, unless you are already in the setter.

More testing, especially when we could not WAIT-FOR in functions, brought me to the conclusion that VOID METHODS seems to be compiling to constructs that are the same as, or very close to, internal procedures, while non-VOID methods compiles to construct that are the same as or similar to user defined functions.

With regard to properties, setters would follow the same rules and have the same restrictions that you would experience with VOID methods and/or internal procedures, while getters would impose the same restrictions as FUNCTIONS and non-VOID methods (e.g. cannot be referenced after an indexed field in an ASSIGN statement and could not halt for user input in older versions ).

In other words, in your case, properties with no getter block can be used like variables, but those with a GET(): END GET. must be treated as METHOD/FUNCTION calls.

The problem is that you may not know if I have implemented a GETTER, or I may implement one later on and have an adverse effect on your code. In principle, if I suspect that these might be code, especially potentially expensive or slow code, behind a property, I will normally put it in a local variable if I am going to reference is more than once.

There are cases where I intentionally write the code so that I can always reference it directly and calculate the value only once when needed, but that requires that you keep the value in a private variable and maintain a flag to indicate if you need to (re-)calculate. You also need to reset this flag for any and all of these properties whenever anything that may have an effect on them changes, which immediately opens the door for human error.

Posted by Peter Judge on 10-Feb-2016 08:08

Do you expect the value returned by the property to change between iterations? If so, you will run into problems since the WHERE only evaluates once.
 
The test code below only displays one message in each case.
 
def temp-table tt1 no-undo
    field f1 as dec
    field f2 as char.
   
def var i as int.  
def var o as PropGet.
 
do i = 1 to 100:
    create tt1.
    f1 = i.
    f2 = string(i).
end.
 
o = new PropGet().
o:GetterProp = 1.0.
o:NekkidProp = 1.0.
 
for each tt1 where tt1.f1 = o:GetterProp:           
    o:GetterProp= tt1.f1 + 1.
                
    message
    'tt1:' tt1.f1 tt1.f2 skip
    'GetterProp' o:GetterProp skip
    'can-find?' can-find(first tt1 where tt1.f1 = o:GetterProp)
    view-as alert-box.    
end.
 
message 'done GetterProp'
        view-as alert-box
 
for each tt1 where tt1.f1 = o:NekkidProp:           
    o:NekkidProp = tt1.f1 + 1.
                
    message
    'tt1:' tt1.f1 tt1.f2 skip
    'o:NekkidProp' o:NekkidProp skip
    'can-find?' can-find(first tt1 where tt1.f1 = o:NekkidProp)
    view-as alert-box.    
end.
message 'done NekkidProp'
        view-as alert-box
 
And the PropGet class too
class PropGet:
    define public property GetterProp as dec no-undo
    get():
        return exp(GetterProp, 2).
    end get.
    set.
 
    define public property NekkidProp as dec no-undo get. set.
       
end class.
 
 

Posted by cverbiest on 10-Feb-2016 10:36

The properties I want to use in this case are rather fixed, they won't change during the iteration.

Getters might pose a problem and definitely a performance hit.

Properties without getters are very fast. Properties with getters ,even the simplest form, invoke a method when queried making them a lot slower.

In my current use case I'll remove the getters on the properties . They are session properties that are queried a lot and I don't want the performance hit of a method invocation anyway.

I'll use the properties in a where clause but I'll proceed with caution.

Thanks for all the answers

Posted by gus on 10-Feb-2016 12:42

not always true. is for for each

--

regards,

gus (gus@progress.com)

"If I set here and stare at nothing long enough, people might think I'm an engineer working on something."

-- S.R. McElroy

> On Feb 10, 2016, at 9:10 AM, Peter Judge wrote:

>

> Update from Progress Community [https://community.progress.com/]

>

> Peter Judge [https://community.progress.com/members/pjudge]

>

> Do you expect the value returned by the property to change between iterations? If so, you will run into problems since the WHERE only evaluates once.

>

> The test code below only displays one message in each case.

>

> def temp-table tt1 no-undo

>

> field f1 as dec

>

> field f2 as char.

>

> def var i as int.

>

> def var o as PropGet.

>

> do i = 1 to 100:

>

> create tt1.

>

> f1 = i.

>

> f2 = string(i).

> end.

>

> o = new PropGet().

> o:GetterProp = 1.0.

> o:NekkidProp = 1.0.

>

> for each tt1 where tt1.f1 = o:GetterProp:

>

>

> o:GetterProp= tt1.f1 + 1.

>

>

> message

>

>

> 'tt1:' tt1.f1 tt1.f2 skip

>

> 'GetterProp' o:GetterProp skip

>

> 'can-find?' can-find(first tt1 where tt1.f1 = o:GetterProp)

>

>

> view-as alert-box.

>

> end.

>

> message 'done GetterProp'

>

>

> view-as alert-box.

>

> for each tt1 where tt1.f1 = o:NekkidProp:

>

>

> o:NekkidProp = tt1.f1 + 1.

>

>

> message

>

>

> 'tt1:' tt1.f1 tt1.f2 skip

>

> 'o:NekkidProp' o:NekkidProp skip

>

> 'can-find?' can-find(first tt1 where tt1.f1 = o:NekkidProp)

>

> view-as alert-box.

>

> end.

> message 'done NekkidProp'

>

>

> view-as alert-box.

>

> And the PropGet class too

>

> class PropGet:

>

>

> define public property GetterProp as dec no-undo

>

> get():

>

> return exp(GetterProp, 2).

>

> end get.

>

> set.

>

> define public property NekkidProp as dec no-undo get. set.

>

> end class.

>

> View online [https://community.progress.com/community_groups/openedge_development/f/19/p/23007/80418#80418]

>

> You received this notification because you subscribed to the forum. To unsubscribe from only this thread, go here [https://community.progress.com/community_groups/openedge_development/f/19/t/23007/mute].

>

> Flag [https://community.progress.com/community_groups/openedge_development/f/19/p/23007/80418?AbuseContentId=d6d180c3-3026-4bdf-b05d-51acb094b5d3&AbuseContentTypeId=f586769b-0822-468a-b7f3-a94d480ed9b0&AbuseFlag=true] this post as spam/abuse.

This thread is closed