×
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 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.