Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Common Procedures

Status
Not open for further replies.

Scott24x7

Programmer
Jul 12, 2001
2,826
JP
So while cleaning the whole bad habits of VFP closet out, another thing I've heard conflicting views on. Certainly a carry over from my FP days, I have a COMMON.PRG file that has all my "custom" routines (including my error handler and cleanup procedures) in it.

Is this still a common practice, and/or a good practice? I know back when I was doing VFP several years ago there were debates over this, and I created a "non-visual" class library that you stuck on the forms which had all these routines in them instead of a SET PROCEDURE TO COMMON.PRG call in the very early stages of the application start, prior to launching the MAIN form, and issuing READ EVENTS.

What is the suggested practice now?
I ask partly because as I'm setting up goAPP, I'm tempted to put the class definition and procedures associated with it into COMMON.PRG


Best Regards,
Scott
MIET, MASHRAE, CDCP, CDCS, CDCE, CTDC, CTIA, ATS

"Everything should be made as simple as possible, and no simpler."[hammer]
 
No, this isn't common practice anymore. Since VFP (and Windows) is extremely good at caching, it's common to have all these functions as separate prgs. I prefer to store them in a separate progs directory. The project manager will take care of adding the necessary prgs to your project.
 
I don't know whether or not it is common practice, but it is certainly not a "bad habit".

Like many decisions in programming, there are pros and cons.

One the one hand, having a single procedure file makes it easy to manage your routines and to transfer them to other projects, as it keeps them all in one place. There are fewer files to keep track of, and fewer items to clutter up your project window.

On the other hand, having each routine in its own file means that, in any given project, you only incoroporate the routines you actually use, which in turn means a smaller EXE (though only slighly smaller in most cases).

I suggest you consider the pros and cons, and do whatever you feel comfortable with.

Note that I am only talking here about the small common utility routines that are not specific to any particular application. It doesn't apply to major functions that make up a large part of an app's functionality.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
Well, I don't have one COMMON.PRG, I have some function/procedure libraries and some nonvisual class definitions (sometimes in same files) and I have a routine going through all _vfp.activeproject.files and building up a metadata dbf of all VCXes and PRGs, so a central routine at startup can take this metadata and do all necessary SET PROCEDURE and SET CLASSLIB. And that solves all the problems with missing some declaration. It does not make the compiler leave out uncalled PRGs, that's true, but I don't aim for the smallest EXE, I aim for the least problems.

I don't have a reason to put everything in one PRG and I "catch" you to again prefer a PRG class. Why? Use a container class, it can nest further container classes. Notice you can create an object from a container class without adding it to a form. A container can "live" standalone. The usual base class for nonvisual, yet VCX classes is "custom", it also is able to add further objects to it via AddObject, but you can't do visually at design time, only at runtime. The container just has the big advantage to be able to nest further classes inside it, you can compose a goApp having an oSetup, oFormhandler, oDatabsehandler etc subobjects, which in themselves are own container class definitions and may host even more helper objects/classes. So the container is the base class of all my nonvisual classes, even if they are standalone and never aded to a form.

Bye, Olaf.
 
Guys, this is all great, and thanks for the perspectives. There are some days I wish I didn't "know more". This is one of them. :)

In fairness I have a few .PRGs for this app, but "COMMON.PRG" I know I've been dragging with me since FPD 2.0. When I moved to VFP, I changed a bunch of stuff in it, realizing it was less about "modern" (1996) programming, and more about "VFP as a better FoxPro". In full disclosure, there are a lot more "PUBLIC's" in there, some of which I know are long since past use, than just my glTipState, but now that I know how to manage it, (I wanted to keep the example simple, and avoid Olaf beating me up too severely for really bad code -- said with all endearment possible. [conehead] But really, I wanted to keep it simple and now that I have this solution, coupled with Tore's brilliant function, I'm starting to get rid of all of them. By next week I should have all those resolved, and I can't leave Tamar out of that one either, she really set the stage for me.) And that brings me to another .PRG point, as I decided to pull that one out entirely. It just seened cleaner that way.

So then I have a couple of other .PRG, one for EZTWAIN, as it is unique in how it interacts with my main application, so I wanted to keep it "clean" as well.
COMMON mostly has error handling, setup and cleanup code in it. So to Mike's point, it's probably fine. However, I have it broken into 2 sections: 1) The "core" functions stuff, and 2) Application Specific calls. For example, in this app, I wrote an extensive process for parsing unstructured data. With the very early call (about line 4 or 5) of STARTUP.PRG (set to MAIN) it calles SET PROCEDURE TO COMMON.PRG. So I get access to those functions anywhere that I need them. That seemed handy enough, though I know I could use an ADDITIVE clause to keep them separate.
While I'm not worried about "Bloat", I'm also conscious not to just pile things on. But in this case, the largest .PRG I have is the EZTWAIN at 200k, then COMMON at 120k. Everything else (there are 3 or 4) are under 15k or less and in the scheme of compute power today, those are all insignificant.

As you guys know, I'm not a "Full time developer" and left the field for over 15 years until deciding to create this app for our enterprise. I may not yet be as "fast" as I used to be, but I know that I am now beyond where I was in understanding and capability, as well as implementing more advanced approaches to development, and for that I think you all greatly.


Best Regards,
Scott
MIET, MASHRAE, CDCP, CDCS, CDCE, CTDC, CTIA, ATS

"Everything should be made as simple as possible, and no simpler."[hammer]
 
I have it broken into 2 sections: 1) The "core" functions stuff, and 2) Application Specific calls.

That's exactly what I do. I have a file called GENERALPROCS.PRG, which contains compleltely generic stuff, like converting a number to an amount in words, or calculating the length of a string in pixels, or calculating the Nth weekday in the month.

And I have another called xxxxPROCS.PRG, where xxxx is a standard 4-letter code for the application. This contains routines that are commonly called throughout the application, but are still application-specific. For example, ValidateJobs(), which performs a certain type of validation at many points in the app.

But really, Scott, I wouldn't worry too much about this. I know you want to bring your programming (and your expertise) up to date, and that is laudable. But, give the pros and cons I mentioned earlier, you should really just do what you feel most comfortable with.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
MikeLewis said:
you should really just do what you feel most comfortable with.

I want to second that thought in that you now have got plenty of input and suggestions. It's hard to pick out just the best or combine all of them, everybody has slightly different overall philosophies. In the end, you have to do what you feel comfortable with, just check whether it conforms to good practices.

This is one of the things where you want a horse and you get a camel designed by committee. In the end, whatever suggestions you take with you, you have to check your overall "horse" goApp for making sense. It is one of these things, that can become the bad pattern of a god class. My idea with managers of certain aspects kind of clicking into slots of goApp is not my original idea, I also just took it from the frameworks I worked with. In the end, goApp is the "god" of the app, but it should also stay out of specific functionalities you do better here specialists for, and this confirms the idea of managers attaching to the goApp object.

GENERALPROCS as Mike mentions them, have no direct involvement with the core functionalities of an app and therefore have no reason to directly go into an application class. Data access also is very common and not application specific to the topic of an application, but it surely is one major pillar of an application and thus totally ok put in there, but a big enough topic to have its own handler or manager.

Bye, Olaf.
 
Thanks guys. At least this one I feel more comfortable with what I'm doing not causing any major conflict in overall design and development strategy. There was a time when I was taking all these procs, putting them in to a "common.vcx" non-visual class, and then putting that object on every form. So as Mike said, if I needed a procedure in the form to format a number to words, then it was there and I would call it. Then there was no call to COMMON.PRG, but every form (and put it at the lowest level baseform for inheritance) would have the "common" class with all its methods. But I didn't really like that, it was a "style" I tried based on the suggestion of some video training course in VFP I did in 2002.

As I fix the rest of my "gX" values, I will look harder at separating the "COMMON" stuff out from the "APP SPECIFIC" stuff, and maybe just split them into two .PRGS, with specialty stuff like EZTWAIN left to itself. (It's huge, but mostly due to massive comments in the code throughout). And since comments don't get compiled in, it doesn't really add that much to the .EXE In fact, I had a peek at my .EXE size earlier, and it's only 6mb, so really not a big overloaded app to begin with.

Thanks guys, this helps a lot. I can stop worrying about this one, and focus more on some of the other "habit breaking" I need to work on.

Best Regards,
Scott
MIET, MASHRAE, CDCP, CDCS, CDCE, CTDC, CTIA, ATS

"Everything should be made as simple as possible, and no simpler."[hammer]
 
Code:
...every form (and put it at the lowest level baseform for inheritance) would have the "common" class with all its methods. But I didn't really like that, it was a "style" I tried based on the suggestion of some video training course in VFP I did in 2002.

Yes, this way you're loading this class into memory multiple times, let each form have an instance of it with potentially individual states in properties you would not make use of. The benefit being all functions are discoverable via IntelliSense. It is a workable concept, too. Making it a separate object makes it expandable and you may switch it with a totally different implementation, given the parameterization and return types stay the same.

You could also have goApp.oCommonFunctions or name it shorter for convenience and then don't need the base form to have it and it being instantiated many times, that would solve that problem. And you can have IntelliSense for an object outside, too, you can trick the editor in looking up the definition of a class by using the [tt]LOCAL var as class[/tt] declaration of variables as a class. It does not make the var that class, it still is initialized with .F. as any variable, but the editor expects it to be that class, this also works with OLE, as in this example:
intellisenseUnbenannt_cmizbq.png


Anyway, I already said I do use PRGs with functions and procedures, too. I rather see them as an extension of the language and also in strict OOP languages, you have native functions, commands, and operators. There is just an annoyance with calls of functions, the calls don't tell about the source of the definitions. From the developers perspective of maintaining code that's bad, but you may prefix function names with f or prg to hint on that and the debugger will help you find out where that call steps into. I still consider it a good thing to have simple functions as what they are, mere functions. Stateless, returning something only based on input parameters, not by any state or history of calls, that doesn't need an object, that can simply be a function. Classes are also not necessary to bundle a topic like Javascript's Math class, they are OK, if the functions are all about a type, eg I like the way you can do something with any string in C# not by using it as a parameter of a string function, but applying a function to it by letting it be a method of that type. In such cases classes are actually types and VFP doesn't have such a thing.

Bye, Olaf.
 
My take on this is that anything that you can think of an extension of the programming language goes into its own PRG. (I'm definitely in the "no procedure files" camp.) So, if I had, say, a function that determines whether a character string is entirely numeric, I'd have IsNumeric.PRG, and then I can call it from anywhere.

Anytime I have a set of related functions, especially, if they work on some common variables, I'd create a class, making the variables into properties, and the functions into methods.

That leaves a group in the middle, which are too specialized to be considered programming language extensions, but don't rely on common data. If there are a group around the same area, I might still turn them into a class.

As for procedure files, I never liked them, though I acknowledge they were required early on. As soon as FP could handle large numbers of PRGs, I stopped using Proc files and never looked back. (Except that I've inherited lots of apps that use them. Worst case was one with a 3MB proc file containing thousands of routines. I couldn't use any of the project search tools on it.)

Tamar
 
Tamar,
I see your point about bloating procedure files.
I like the idea of a group of related procedures though. I think I'll be pulling some out of my common procedure file, as the parsing of OCR procedures are all there, but only 2 forms actually use it. So I could non-visual class those, then pop them onto those two forms, and they are the only things that need/want them. That seems like a good way to go. I don't like having dangly PRG's particularly, classing them seems like it might solve that. Then I can have a PARSEOCR class, that just gets used when I need that.
I downloaded a couple of articles from Doug Hennig yesterday, one that seems to fit this topic "Long Live PRG's!" so will look at the suggestions there as well.
I think to be fair, the biggest thing that I'm "stuck" in on the COMMON.PRG side is error capture and handling, which is the same set of routines that I've been using since FP2, I think it was originally written by Lisa Slater-Nichols, and published an a FP Advisor "back in the day". But it's been a great resource in that it captures the state of everything at a crash and writes it out to VFPERROR.dbf (renamed by me, originally was called PRO2EROR if that rings any bells. I understand VFP has a whole new way of approaching error management, but I've never fully understood it.


Best Regards,
Scott
MIET, MASHRAE, CDCP, CDCS, CDCE, CTDC, CTIA, ATS

"Everything should be made as simple as possible, and no simpler."[hammer]
 
the biggest thing that I'm "stuck" in on the COMMON.PRG side is error capture and handling,

Actually that's one area that I definitely do not put in a common procedure file. My theory is that anything to do with error-handling should be as independent and free-standing as possible. So I prefer not to assume the existence of a SET PROCEDURE at the point when a error is generated.

This is probably totally unnecessary. But it is one of those things I have always done and which I will probably never change.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips and downloads
 
I agree with Mike on the topic of error handling. To solve that: Anything, that should be reliably found can be added to Main.PRG after your normal main code you can use this PRG for procedures and also some class definitions, perhaps. Though the metadata approach of the framework I use to make all necessary SET PROCEDURE and SET CLASSLIB calls is very reliable and needs nothing to be within Main.PRG as permanently on the call stack and thus impossible to miss.

I said I rather aim to not miss something than to have the smallest possible EXE, I wouldn't go as far as putting every definition into Main.PRG, but the error handling is one nice example. I do the ON ERROR setting within Main.PRG and it makes sense to refer to a procedure within this PRG to also never let it go from the call stack at runtime. The framework I use does not do so, but it would make sense. If anything else is missing, at least the error handler would handle this error in the way I like with all logging and storing meta info at runtime helping me to reproduce and find an error.

Tamar says there are at least two camps and you can decide here, what's your choice, this is one of the areas of developer taste about what is best and we all can live with each other.

I agree huge procedure files are not the way to go, that points out non-grouping, simply cramping everything into one PRG file is just a heap of functions. It is possible though, and it makes just one place to find all functions. Open up a PRG and in the menu choose tools->docuemnt view and you have a nice overview of all constants, procedures/functions, and classes defined in that PRG. This gives you about the same navigation through the PRG as the Combobox of the method list in the head of the editor of a visual class, though you can also use the methods tab of the property window in visual class editing.

Bye, Olaf.

 
I suspect the error handler you're using came from Pat Adams. I don't actually remember Lisa publishing one, but Pat definitely did.

My only comment about that is that it was very much designed for FP, not VFP. Not urgent, but at some point, I'd recommend reading Doug Hennig's articles on error-handling in VFP.

Here's his original article: He revisited the topic when VFP 8 came out with Try-Catch:
Tamar
 
Hi Tamar,
You are right, it was Pat Adams, now that you mention it. And yes, I've known it was FP focused for a long while, but hadn't been able to find something that talked about modern errors in VFP. Just downloaded the two articles, so that is great. At some point in the near term, I will go through them with the aim of modernizing the error process. In fairness to PRO2ERROR, it was pretty robust, and has served me pretty well with a few modifications over the years, but I know VFP did a lot to improve and enhance the error handling process, so I'm happy to have a source for modernizing it.
Thanks for that,
-S


Best Regards,
Scott
MIET, MASHRAE, CDCP, CDCS, CDCE, CTDC, CTIA, ATS

"Everything should be made as simple as possible, and no simpler."[hammer]
 
No question. Pat's error handler was the standard for FP, but VFP gives you a lot more options to manage errors.

Tamar
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top