<<In my Fox2.6 days, I had a lengthy file alled "COMMON.PRG", which I would set with the SET PROCEDURE TO <proc> in fox.
This had all my handy-dandy UDF's that I'd call, as well as my ERROR Handler, and SYSTEM INITIALIZATIONs.
As I get deeper into VFP, I find that I can now put those items into a "Custom" class.
That then gets (here's where I get hazey...) "Instantiated" in my "MAIN" form, and then everything can get at these
functions as they could before. Is this a good idea? Should I stick with a .PRG, or should I class these items?
What is the advantage/disadvantage? Is it hard?
I think the thing that is killing me is, I have been a really good 2.6 developer, and I don't want to start
some bad habbits that will cause me huge problems later. What's the pannels suggestion for this one???>>
There are a number of advantages to using OOP instead of the tried and true procedural route. Some of the advantages are immediate, some will only apply in a more advanced environment.
Personally, I hate SET PROC TO. I've always considered it a nasty old xBase kludge. It drives me crazy when a function is called in a piece of code and the function is part of a SET PROC TO that encompasses a half-dozen program files. How do you tell which file has the (usually offending) function?
An OOP alternative is:
*** MyCustom.prg
RETURN CREATEOBJECT("MyCustom"
DEFINE CLASS MyCustom AS CUSTOM
pcSysDrive = ""
pcRootPath = ""
PROTECTED pnCriticalVal = 0
roAdoRS = ""
roAdoConnection = ""
*** and what ever other properties you need
FUNCTION SetEnvironment
WITH THIS
.pcSysDrive = SYS(5)
.pcRootPath = SYS(2003)
ENDWITH
RETURN
FUNCTION OpenDBF
LPARAMETERS tcDBF, txOrder, txWorkSpace
*** your tried and true "open a DBF" code goes here
RETURN
FUNCTION CloseDBF
*** your tried and true "close a DBF" code goes here
RETURN
FUNCTION OpenADO
*** open an ADO record set
RETURN
FUNCTION MoveADO
*** navigate through an ADO record set
RETURN
FUNCTION CloseADO
*** close an ADO record set
RETURN
FUNCTION MyUltraTrickStuff_1
*** your tried and true ultra trick code goes here
RETURN
FUNCTION SetCriticalVal
LPARAMETER vnNewVal
IF VARTYPE(m.vnNewVal) = "N"
THIS.pnCriticalVal = m.vnNewVal
ENDIF
RETURN
*** etc, etc, etc
ENDDEFINE
*** End of MyCustom.prg
*** MyApp.prg
*** initialize the memvar that will hold your custom-class object
goCust = ""
*** load your custom-class into the memvar... aka "Instantiation"
DO MyCustom.prg WITH goCust
WITH goCust
.SetEnvironment()
.OpenDBF("MyDBF", "MyTag"

.OpenDBF("My2ndDBF", "Tag2", 2)
ENDWITH
*** other code may go here...
goCust.MyUltraTrickStuff_1()
RETURN
*** End of MyApp.prg
First off, this is what's happend in this example:
MyCustom.prg has a bunch of properties (formerly your global memvars) and functions/methods (formerly your functions/procedures).
MyApp.prg initializes a memvar (goCust) which is fed to MyCustom.prg. MyCustom creates the "custom" object, which is stored in goCust. (ENORMOUS subtlty here... MyCustom.prg functionally has only one line of code: RETURN CREATEOBJECT("MyCustom"

; but this one line of code calls the DEFINE OBJECT, which builds the MyCustom object).
On returing from MyCustom.prg, all the properties and methods in MyCustom.prg are accessible via the goCust memvar.
Because goCust was declared at the beginning of MyApp.prg, it is scoped to all of MyApp.prg and any programs, forms, menus, etc. that are called by MyApp. Its functionally the same as defining goApp as PUBLIC, without the overhead.
In this very simple example, the good stuff in your old procedure file is now available in the goCust object with the advantage that you can (fairly) easily track where the procedures are coming from... OOP tends to be self-documenting. Notice that there was no "SET" required to call the class-creation program (DO MyCustom.prg WITH...)
Also, critical information (in this example, the system drive and root directory) are stored in one place... the custom object.
At this point, you may be saying "So what? There's nothing here that I haven't already done in procedural Fox code"
But there are things available via OOP that you can't do procedurally. For example, ever had a global memvar overwritten in some procedure, which caused everything to go BOOM? Remember how hard it was to track it down?
If that global memvar became a protected property of your custom class, it COULDN'T be changed unless you changed it
from within the class. Typically, that change is done with a method of the class (i.e. goCust.SetCriticalVal()).
That method becomes something known as a class "interface", one of the OOP mechanism used to improve the encapsulation (formerly known as modularity) of your code.
As Microsoft's stuff becomes more interoperable, you may find yourself using things outside of VFP. It used to be really tough because VFP didn't play nice with ActiveX components, but VFP 7 is supposed to have much improved COM/DCOM support. Which is good... very good. If you're really carefull with your class encapsulation, you'll be able to start reusing your VFP components in other strange and unexpected places, making your life much more interesting (no suprise there) and easier (huge suprise!). This is the REAL benefit of utilizing OOP.
HTH,
Thom C.