Link to home
Start Free TrialLog in
Avatar of formadmirer
formadmirerFlag for United States of America

asked on

VFP Public Variables

Hi all. This program I am working in assigns nearly 60 public variables during startup. They are not released until the program closes.

I was wondering if this is normal/typical, and if there could be any problems associated with this many variables being held in memory.
SOLUTION
Avatar of peterhupp
peterhupp
Flag of Canada image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Avatar of Olaf Doschke
Olaf Doschke
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of formadmirer

ASKER

I was not previously aware of the issue regarding a public variable 'disappearing' when passed to a Procedure or Function.

AFAIK we've never had any issues with the use of these public variables in our program, and they are all preceded with a lower case 'p' to safeguard their use throughout the program.

I just wasn't sure what kind of memory each of these variables was likely to consume, and didn't know if that was something to be concerned about or not.

They are mostly used to store path and file locations, and I added a few like one that holds my MySQL connect string.
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Usage of public vars is no go for me. tT seems I'm the only hardliner here. What I agree is, that the memory usage and the amount of them is not a problem. VFP allows infiinite array elements, the memory is your limit, nothing else (in previous versions there was a limit of 65000 elements per array). From that perspective 60 public vars are a small number.

Just take some third party module from a developer having had the same idea about a name of a poblic var and you have a problem. That's the hardest problem of public vars. Another side of them is, you have to know their names, Have goApp.oConfig.property = value and create this goApp during development time and you can find your config properties via Intellisense. Even just that would speak against such public vars and in favor of a goApp object you extend with subobjects.

Also you don't need a connection string public, you just will have one central class connecting to the server, and only that needs to know the connection string. So in this sense the need of public vars show a lack of centralising code.

In regard of config, create a DBF or INF or XML file with simple name/value pairs, configpropertyname, eg data dir and configvalue, eg path to data. Read that into an EMPTY object.

Addproperty(goApp,"Config",createobject("Empty"))
Use config (config dbf has fields property and value)
Scan
   Addproperty(goApp.Config,config.property, config.value)
Endscan 

Open in new window

That's that  in very short, you can add code checking for double properties, invalid property names, you can also use a primary index to avoid double names.

It's all about better organising yourself and better describing the scope of things.

All I really need in any place is an identifier for the currently logged in user and the currently selected lanmguage, if my app is localised. I may need some paths, but that is having a smaller scope, eg only reporting modules need to know location of frx files, if I leave them external for dynamically changing them at runtime. But the whole application doesn't need top know their path.

And from that perspective 60 is a huge number, you can have the same overview about your config values in a config.dbf and then add some more fields to denote a type and usage or whatever to organise yourself better.

Bye, Olaf.
One more thing you can do to avoid a name overlap, even in such a common name as goApp.Config is, just create a subobject goApp.MyApp or goApp.MyCompany, and add everything else at that level. There is no need to avoid a name conflict of goApp, as you will not really be able to make use of two frameworks at the same time. Even if there would only be the need to merge their application class. Therefor it's also good as a framework developer to keet that application class itself very lightweight and let modules dock to it.

Bye, Olaf.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Olaf, if you are so strict in public variables usage then you should not use even the goApp :-)

goApp is just "hardcoded" reference to the "application pyramid top" which is not good practice. Each application should have its own reference named ThisApplication and this object should be visible just in the application thread...

So you should not use goApp as a public variable but you should create private variable in a main program/form and name it ThisApplication. This will ensure compatibility even in multithreaded environment when it will be implemented to VFP language. :-)

OK, more seriously now: To refactor debugged and working code designed in FoxPro 1/2.x is waste of the time. And almost everybody has such code in a drawer... You can

To avoid problem with hidden public variable (which is also valid for private variables) you may simply enclose the variable name in parenthesis when calling a function or procedure:

llResult = MyBadFunction( (m.gcGlobalPath), m.AnotherParam)
Application pyramid top, Well, that's how it is, I don't see any difference if declaring aprivate var in main or a public var somwhere in a factory or  whatever is taken to create object. I can live with this one hardcoded reference, as I can make use of goApp.MyApp.translate() or goApp.MyApp.userid or goApp.MyApp.nMySQLHandle. I don`t follow you, how a private variable would be visible in multiple threads and public vars not.

You can also argue this is really not just reducing the number of public things, it's just using properties instead of variables. But it's all about the namespace(s) and the hierarchy you build with it.

If it ain't broke, don't touch it. I mainly agree, but you can put some effort in it, you don't need to do it in one go, and it will help if you use third party code to incorporate this into the "application pyramid".

Bye, Olaf.
Evidently this is a hot topic and one that often leads to somewhat heated debates, as I saw on the fox. wikis.com page.

All I needed to know is if the code I am working on is OK in it's current state with using 60 public variables during the startup process.

I now know that maybe this isn't ideal coding practice by today's standards, but also that it is not unheard of and that actually 60 public vars isn't all that many, and won't have a negative impact on system memory available.

Thanks to everyone for their input!
> 60 public vars ... won't have a negative impact on system memory available.
How do you get that idea, at all?

Public variables don't take more memory than local, they just have a global scope, they don't release.

The impact on memory is of course depending on what is put into them. But a path is just a few bytes, magnitude 100 perhaps. If that's the mean memory usage we talk of 6KB. Public vars don't effect memory or performance.

And the main question can also be answered: If it works, then it works. And it's not probable the 60 public vars were introduced just in the last few days. I assume the app ran quite some time and so that already answers that anything you find can work. But that's not answering the question if it's good practice, if it's usable, maintainable, understandable, extensible. There are many aspects of code that should be pushed to an overall better quality.

In larger and longer running projects you can often see the effect code quality degrades over time, an application wears out, get's less extensible, has too many dependencies and side effects of changes and is less good to refactor.

You can detect errors in variable scope definitions quite easy. If some value get's passed to very many methods of a class, then it's a sign that parameter should rather be a property of the class, püerhaps. As public vars don't need to be passed on this bad design will not be revealed.

http://fox.wikis.com/wc.dll?Wiki~PublicAndPrivateVariables lists some more interesting characterisitcs of public vars and their redifinition: If you create a public var in main.prg and redefine it somewhere via PUBLIC you don't get an error. Sounds nice, but a redefinition of it indicates that programmer doesn't know it's a public var already and most probably has another usage of it. Surely it will not only be redeclared, but also set to another value, and that then breaks code at other places depending on the initial value. Those are hard to understand and debug errors. You'll first look into main and see the value assigned is correct and then scratch your head, until you finally will perhaps use Code References to see where else this variable is set.

And defining variables as private in main doesn't change that.

The answer in my oppinion is to change from public informations as you have in public variables to available application modules not only holding the information but also being able to work with them. Your oop design can reflect the real world, implementing colleagues having a certain job and knowing all the needed rules. And you rather delegate tasks to them then just ask them for the infos needed to do something at the caller level.

That thought keeps you from reimplementing the same code more than once and that makes use of the most important pattern of modern development: loose coupling. Keep close together what belongs close together and loosely couple these objects to work with related objects. Rather program in a way "do this form me", than "give me the information I need to do it my way".

A database manager class for example will connect to the database and all any other component may need is the succcess of connection or an error level, if there is, and the connection handle.

Keep these jobs or roles small, eg a database manager should manage database connections only, perhaps, and leave data access to dataaccess classes, which can all inherit from a base class and all make use of the database manager, so the database manager can also log and do statistics on how many components request a connection and if it's perhaps a good idea to make more connections and load balance or jsut use one connection, to keep it opened or close it at times of very low usage. This is not the job of the single dataaccess objects anymore. And a public variable may hold the connection handle, but can't do that kind of logic, it's just a dumb variable.

Bye, Olaf.