× The internal search function is temporarily non-functional. The current search engine is no longer viable and we are researching alternatives.
As a stop gap measure, we are using Google's custom search engine service.
If you know of an easy to use, open source, search engine ... please contact support@midrange.com.




On Tue, 1 Feb 2005, Ala, Michael A wrote:

What is the best way to perform Procedure prototyping
I would like some rules

Here are some rules that I like to use, that come to mind:

a) Any prototype or other definition (data structure, etc) that's accessible from outside the module or service program should start with a prefix that identifies where it came from.

For example, if I have a service program for working with orders, I might use ORDER_ as the prefix. I'll name the service program Procedures might be called ORDER_new(), ORDER_open(), ORDER_read(), ORDER_update(), etc. Data structures might be called ORDER_header_data, ORDER_line_item, etc.

This way, I won't run into two programs that use the same procedure names, etc. It also makes the code easier to follow, because the next guy who comes along knows exactly where to look for a given procedure.

b) Input-only parameters are always coded with either CONST or VALUE. I usually use VALUE for numeric fields, and CONST for anything else (mainly because that's what I do in C programming) but if I'm going to need a temporary copy of the input parm, I'll sometimes use VALUE instead.

c) The return value always indicates whether the procedure succeeded or failed. Sometimes it goes a step further and returns a length or a pointer, where a special value (such as -1 or *NULL) indicates that an error occurs. If it doesn't return a length or pointer, then it'll usually be an indicator set to *ON for success or *OFF for failure. (Though, I've used integers instead of indicators in the past, so I haven't been completely consistent)

d) Return values are never large fields. Large fields (such as longer strings) are always done as parameters rather than return values. This is for performance reasons -- passing a string by reference is much faster than returning it. Though, I'll break this rule if performance isn't critical and it's significantly more convienient to have a return value.


I am not sure if I am performing any steps that are unecessary
[SNIP]
This is what is copied in
D GetGroup        PR             1A   EXTPROC('GETGROUP')
D  $Group                       10A
D  $Cust#                        8S 0 CONST OPTIONS(*OMIT)
D  $Item#                       25A   OPTIONS(*NOPASS)

The keyword EXTPROC is unnecessary here because the procedure was already named 'GETGROUP' (RPG will convert to all uppercase by default.) If you wanted to force it to be a lowercase name, you'd need EXTPROC, or if you wanted to call a procedure where the name needed to be lowercase, or something else about it didn't conform to RPG's defaults (such as using CL's parameter convention, or whatever) then you'd need an EXTPROC statement.


That's the only thing that looks redundant to me about this definition.

You may want to consider coding EXTPROC(*CL:'GETGROUP') on your prototype since you're returning a 1A value. Without this a CL program using the CALLPRC command to call your RPG will have to use a 2A value for the return type or it'll get an error.

Also what are the advantages to setting up multiple sub-procedures in a single source member? What limitations does this have?

I find it easier to maintain when I have fewer members to look through. If I have a program that calls 50-60 subprocedures (which isn't unusual), I'd be very unhappy if each one is in a different source member!!


Also, having multiple subprocedures in a module makes it possible for there to be variables that are shared by those subprocedures, but are not available to the caller. This is extremely useful.

For example, my FTPAPI service program allows the following calls:

   x = FTP_conn('ftp.example.com: 'userid': 'password);

   FTP_put(x: '/path/to/file');

   FTP_get(x: '/path/to/other/file');

   FTP_quit(x);

These various FTP routines are able to operate on the same FTP session because they're able to share data with one another. That data is not available to the application that calls them, which makes the FTP programs more stable, since they don't have to worry about another program changing their variables.


The disadvantages? Usually the one I run into is open files. Files can't be scoped to the subprocedure, they're always scoped to the module -- so when I've got a modules in a service program that does a lot of different functions, it'll usually open up ALL of the files that can potentially be needed. Since the srvpgm doesn't know what routines the caller is going to call, it'll just open up everything on the first call to any exported procedure. This can lead to a lot of unnecessary files being open, and unnecessary object locks.


It's not usually a big deal, though. There are very few times that someone needs exclusive use of objects, except during the nightly backup when everyone has to sign off anyway.

If it's a problem, one easy way to solve it would be to break the program up into more modules...

The only other disadvantage I can think of to having many subprocedures in a given program is that if you've got TOO many, the program gets large and difficult to maintain. Of course, you can always break it into modules (without breaking compatibility) later if it starts getting too large.

What's the advantage of putting everything in a separate member?! That seems like it would be a huge nightmare. In my experience, that leads to people writing large monolithic programs that are hard to re-use. Just like we used to. And then you don't gain much from the ILE model since your modules are basically just old-style programs that are statically bound.

Of course, that's just based on my experience -- others may have seen separate members work out nicely. I really like having the ability to have procedures share data that's hidden from the caller, though. Especially with files being global. It just makes for a much better environment, IMHO.

As an Amazon Associate we earn from qualifying purchases.

This thread ...

Replies:

Follow On AppleNews
Return to Archive home page | Return to MIDRANGE.COM home page

This mailing list archive is Copyright 1997-2024 by midrange.com and David Gibbs as a compilation work. Use of the archive is restricted to research of a business or technical nature. Any other uses are prohibited. Full details are available on our policy page. If you have questions about this, please contact [javascript protected email address].

Operating expenses for this site are earned using the Amazon Associate program and Google Adsense.