Pass inter-objects parameters by name


Link to this posting

Postby Ursego » 19 Feb 2013, 22:28

To pass parameters between objects, use one of methods where parameters are accessed by a mnemonic name rather than a meaningless array index.

You could say: "So foolish advise! Isn't that obvious?". Yes, it's obvious for you and me, but not for everybody... I created this topic because I worked many years in an application where parameters were passed using a structure with a few arrays - one array for each built-in datatype, something like that:

Code: Select all
lstr_parm.long_args[1] = il_emp_id
lstr_parm.long_args[2] = il_dept_id
lstr_parm.string_args[1] = is_first_name
lstr_parm.string_args[2] = is_last_name
lstr_parm.date_args[1] = id_birth_date
lstr_parm.date_args[2] = id_hire_date
lstr_parm.obj_args[1] = dw_header
lstr_parm.obj_args[2] = dw_items

The index-by approach is extremely inconvenient and terribly bugs-prone :evil: !!! Imagine, that a window can be open from different places in the application, with a similar, but not absolutely identical sets of parameters in each case. And even more: some of these sets (or all) can be changed in the future! If, one day, you want to pass one more parameter, you will occupy the next available slot (i.e. the next unused array index). But that slot can be already in use by another object, which opens the same window, so you need to skip that slot! And what if that window is open from 8 different scripts which pack different sets of parameters? Brrrrr!!!!

There are a few alternative methods, where parameters are written and read using mnemonic names. You have no clue what is passed via string_args[8], but the situation is absolutely different if the parameter is named "cust_status"!

In general, PowerBuilder has 4 methods of passing parameters by name.

Method #1 - a custom NVO or structure is individually created for each parameters set.

Advantage:
@ Type safety.
@ All data types can be passed (including arrays, structures and pointers to objects).
@ Convenience working with nested data structures. You can use dot notation to access them directly, with no need to cast, for example:

Code: Select all
uf_validate_postal_code(inv_parm.inv_address.is_postal_code)


Disadvantages:
@ You have to create a brand new NVO or structure each time you need to pass another set of parameters. That will fill your PBLs with many objects, used only once.
@ Extra maintenance efforts: to change passed sets of data, you have to check out / check the structure/NVO.

If you choose this method, then it's better to use NVOs (rather than structures) since they can have comments and be inherited.

Method #2 - one universal NVO or structure is used - with all possible parameters, existing in the application.

Similar to Method #1, but without its first disadvantage. Each time you need to pass a parameter, which has not been passed previously, you simply add a new field to that NVO or structure. If there are a lot of parameters in the application, then the object will not be extremely lightweight. But that can be a problem only in theory. Practically, no one in the world can feel any difference between passing parameters objects with 10 and with 100 fields, so you can definitely consider this option.

Method #3- parameters are passed as one string with a separator between key/value pairs (like "emp_id=123|dept_id=17|status=A").

If you choose this method, then use class n_cst_string of PFC. It has ready functions of_SetKeyValue and of_GetKeyValue, which do for you all the work of packing/unpacking parameters to/from the transportation string.

Advantages:
@ No need to create tens or even hundreds of custom structures or NVOs for each individual case, so the PBLs will be less crowded.
@ Less maintenance efforts - you don't have to check out /check in that structure or NVO when passed sets of data are changed. You only change the packing and the unpacking scripts.

Disadvantage:
@ Only scalar primitive types can be passed, but not arrays and structures (at least in an easy and not-ugly way), and not pointers to objects. That makes the method absolutely unsuitable (do you want to be unable to pass a structure or a DataStore to a Window among other parameters?).

Method #4 - one universal NVO, mimicking hash table, is used all over the whole application.

That is my favorite method. In that NVO, you create instance variables for frequently used parameters (usually, each application has 10-20 such parameters) in the same way as in Method #2. But rarely used and on-time parameters are transported with help of getter and setter. You can download my ready solution from here. The NVO n_parm has functions uf_set and uf_get, which do for you all the work of packing/unpacking parameters to/from the transportation object.

Advantages:
@ No need to create tens or even hundreds of custom structures or NVOs for each individual case, so the PBLs will be less crowded.
@ All data types can be passed (including arrays, structures and pointers to objects).
@ Less maintenance efforts - you don't have to check out /check in that structure or NVO when passed sets of data are changed. You only change the packing and the unpacking scripts.

Disadvantages:
@ Lack of type safety for parameters which don't have their dedicated instance variables. The suggested NVO n_parm physically transports parameters in variables of type any. Its first version had setters, overloaded for different types, and getters like uf_get_s for string, uf_get_i for integer etc., but that solution was too unwieldy, so I decided to sacrifice the type safety (after all, you will get a runtime error).
@ Less convenience (compared to Method #1) working with nested data structures. Before reading the fields of the passed structure or class, you have to unpack it into an interim variable in order to cast any (returned by uf_get) to its actual type. Do you remember uf_validate_postal_code(inv_parm.inv_address.is_postal_code) from Method #1? In Method #4, it will be looking like that:

Code: Select all
n_address lnv_address

lnv_address = inv_parm.uf_get("address") // cast "any" to "n_address"
uf_validate_postal_code(lnv_address.is_postal_code)
User avatar
Ursego
Site Admin
 
Posts: 131
Joined: 19 Feb 2013, 20:33



IF you want to ((lose weight) OR (have unbelievable (brain function AND mental clarity))) THEN click:




cron
free counters

eXTReMe Tracker