iin() + global functions overloading

Share this topic:



Link to this posting

Postby Ursego » 19 Feb 2013, 21:34

Writing Oracle PL/SQL code, I always enjoy the ability to use the SQL's in clause in a procedural environment:

Code: Select all
if v_day in ('SATURDAY', 'SUNDAY') then
   -- do something
end if;

Of course, we can mimic it in PowerScript using the choose case construction (the price - one extra line of code):

Code: Select all
choose case ls_day
case 'SATURDAY', 'SUNDAY'
   // do something
end choose

Unfortunately, it's impossible to utilize the choose case construction to assign the comparison's result to a Boolean variable. :( To do that, we need to use a Boolean expression with OR:

Code: Select all
lb_weekend = (ls_day = 'SATURDAY' or ls_day = 'SUNDAY')

That solution is not very elegant - a same variable is mentioned in code more than once. And if you need to compare with 30 values, not with just 2? Besides, we, database people, love normalization :lol: .

So, let me introduce the iin() function ("internal in"). It reports if the value, passed as the 1st argument, appears in the array, passed as the 2ndt argument:

Code: Select all
lb_weekend = iin(ls_day, {'SATURDAY', 'SUNDAY'})

Of course, you can use a preliminarily populated array:

Code: Select all
string ls_days[] = {'SATURDAY', 'SUNDAY'}

lb_weekend = iin(ls_day, ls_days[])

It's totally impossible to use an array with choose case - you are forced to write a whole loop fragment instead of a single line of code with iin()!

One more example - this time with numeric data:

Code: Select all
if iin(ll_employee_id, {123, 456, 789}) then

You can ask: how did I overload a global function in PowerScript? It's impossible! Not for me - I have a personal permission from the president of Powersoft Sybase SAP! Ok, now I will demonstrate a simple trick. It's true that we cannot overload global functions in the Function Painter, but the source code can pass through a surgical operation! So, firstly create a normal, not-overloaded global function, save it and re-open in with "Edit Source". Then add the needed overloaded versions manually! See an example in the source of iin() function which appears next - it includes 3 overloads: for string (also used for char), for long (also used for int) and for PowerObject - you can save the code as iin.srf file and import it to your application:

Code: Select all
$PBExportHeader$iin.srf
global type iin from function_object
end type

forward prototypes
global function boolean iin (string as_val, string as_arr[])
global function boolean iin (ref powerobject ao_val, ref powerobject ao_arr[])
global function boolean iin (long al_val, long al_arr[])
end prototypes

global function boolean iin (string as_val, string as_arr[]);
int   i
int   li_upper_bound

li_upper_bound = UpperBound(as_arr[])
for i = 1 to li_upper_bound
   if as_arr[i] = as_val then
      return true
   end if
next

return false
end function

global function boolean iin (ref powerobject apo_val, ref powerobject apo_arr[]);
int   i
int   li_upper_bound

li_upper_bound = UpperBound(apo_arr[])
for i = 1 to li_upper_bound
   if apo_arr[i] = apo_val then
      return true
   end if
next

return false
end function

global function boolean iin (long al_val, long

al_arr[]);/**********************************************************************************************************************
Dscr:   Reports if a value, passed as the 1st argument, appears in the array, passed as the 2ndt argument.
      Mimics the action of SQL's IN clause.
      Overloaded for string (serving also char), long (serving also int) and PowerObject.
      To see the overloads, open the function in the "Edit Source" mode.
      
      Examples of use:
      
      if iin(ll_cust_id, ll_best_customers[]) then...
      if iin(ls_city, ls_best_cities[]) then...
      if iin(acb_clicked, lcb_buttons[]) then...
      
      List of values can be inserted inline using brackets - {..., ...} - to avoid the need to declare an array:
      
      if iin(ll_cust_id, {123, 456, 789}) then...
      if iin(ls_city, {"Toronto", "Ottawa"}) then...
      if iin(acb_clicked, {cb_ok, cb_cancel}) then...
-----------------------------------------------------------------------------------------------------------------------
Arg:   value to be checked (string, long or PowerObject)
      array to search in (must be the same type as the first argument)
-----------------------------------------------------------------------------------------------------------------------
Ret:   boolean
-----------------------------------------------------------------------------------------------------------------------
Log:   10may2012 Michael Zuskin   Initial version
**********************************************************************************************************************/
int   i
int   li_upper_bound

li_upper_bound = UpperBound(al_arr[])
for i = 1 to li_upper_bound
   if al_arr[i] = al_val then
      return true
   end if
next

return false
end function


Usually, we don't compare values of types other than int/long/char/string in a IN-like comparison, but if that happens then you can add more overloads. I have found the the function is useful in comparison of visible controls (for example, to say "if one of the following buttons clicked then..."), so the overload for PowerObject was also created.

I have described how to overload global functions only for the sake of overloading existing global functions if a need arises. Don't create new global functions (the reasons are described here). If the old global function, being overloaded by you, would be created as an object's method (i.e. in the right way), you would not be forced to use the described trick to overload it.
User avatar
Ursego
Site Admin
 
Posts: 112
Joined: 19 Feb 2013, 20:33

Link to this posting

Postby erasorzO » 26 Nov 2015, 11:28

Hello Michael,

I wonder why you use the REF keyword in the prototype of the function :

Code: Select all
global function boolean iin (ref powerobject apo_val, ref powerobject apo_arr[]);


An object is anyway passed by reference...
erasorzO
 
Posts: 2
Joined: 26 Nov 2015, 11:17

Link to this posting

Postby Ursego » 27 Dec 2015, 16:54

There are situations when we pass objects by value and it doesn't work. Don't ask me why - PB is so strange... I believe you if you say it would work by value in that case. And I understand what you mean (you ask why I use "pointer to pointer" instead of a "pointer"), but we simply always pass objects by ref and it always works.
User avatar
Ursego
Site Admin
 
Posts: 112
Joined: 19 Feb 2013, 20:33

Link to this posting

Postby erasorzO » 12 Jan 2016, 11:26

It's strange because I've never used REF when I pass an object and I had no issue with that...
erasorzO
 
Posts: 2
Joined: 26 Nov 2015, 11:17

Link to this posting

Postby Ursego » 03 Feb 2016, 08:58

REF keword acts as a comment for developers. It is not forced by the compiler, but that optional keyword can help understand scripts, especially when the called function has a mix of "in" and "out" arguments.
User avatar
Ursego
Site Admin
 
Posts: 112
Joined: 19 Feb 2013, 20:33


Return to Tips and Tricks

Who is online

Users browsing this forum: Google [Bot] and 1 guest


iin() + global functions overloading

Share this topic:


If you think that this site is not too bad, please LIKE it in Facebook. Thanks!





free counters

eXTReMe Tracker