Plateforme Level Extreme
Abonnement
Profil corporatif
Produits & Services
Support
Légal
English
Commonly misused and abused VFP features
Message
Information générale
Forum:
Visual FoxPro
Catégorie:
Autre
Divers
Thread ID:
00310951
Message ID:
00311810
Vues:
38
Hi Jim,

Putting up a list of things to do or not to do is often seen as a 100% to follow rule. We've seen this with the index on DELETED() just recently. I hope you don't mind when I jump in here with some examples where they might be useful or some more reasons why they should be avoided...

>1: Inheritence has to be the single most commonly misused feature of all OO languages.

Inheritance is easier to use and implement than most other technologies for reusing code. It's just creating a new class and making some enhancements. Because it's so easy, it's so easy to misuse. It's far more easier than using all these design patterns to avoid inheritance.

Why is inheritance bad if it's overly used? Because the design gets complex and hard to understand and maintain. Others say, because the design is simply plain wrong.

If you in your design feel the desire that you actually need multiple inheritance, because two different classes have the functionallity you need in one class, that's a sign you got something wrong. In such cases you use inheritance to transfer features to other classes, not because the subclass has a "is a" relationship with the parent class.

>2: SET FILTER TO ... is very often used where another construct would do the job much more efficiently and with better performance.

This really depends on the kind of application you are developing. If your goal is a Client/Server application, even if you only access local databases, SET FILTER is often wrong. But if you decided not to develop a client/server application, SET FILTER has its place.

As a side note, SET FILTER is what VFP internally executes if you have a SELECT INTO CURSOR statement that is fully optimizable.

SET FILTER is useful, if you a) display large junks of data, and not only a subset as you would do in a Client/Server application and b) you don't issue SET FILTER several times for the same alias. If your code saves the old filter, sets a new one and restores it, there's clearly something wrong in a VFP application. In a FP 2.x this behavior made sense, because we had only 25 or 225 work areas, and this technique should save work areas, but in VFP we have more than 32000 work areas in each of the more than 32000 private datasessions. There's no need to use such practice to avoid using a table again with a different filter (as SELECT INTO CURSOR does it).

>3: & the macro expansion feature is too often used where it is either not necessary or ther is a bettter way to accomplish the same goal.

Macro expansion is sometimes the only possibility, and sometimes more readable. Suppose, I've the following to code snippets when lcAlias is the current alias:

? &lcAlias..Field

? EVALUATE(m.lcAlias+".Field")

Which one is more readable? Macro expansion should not be over-used, but it should not be avoided at any cost, neither. As a basic thumb of rule:

a) Use naming expressions whenever possible. A naming expression can be used for all commands where a name is required as part of the command. A name is a tag name, a variable name, an alias, etc. For example:

USE (cTable)
REPLACE (cField) with Value IN (cAlias)
SET ORDER TO (cTag)
INDEX ON expression TAG (cTag)

b) Use evaluation when you replace an expression that is not used directly by VFP. For example, you can use:

STORE EVALUATE("expression") TO (cVarName)
IF EVALUATE("expression")
oRef = EVALUATE("expression")

c) Use macro substitution for two reasons only: If the code actually substitutes part of a command, and not just a name or an expression. And if it increases readability. A typical usage can be:

USE table &cOptions

Be aware that in commands that evaluate the expression further, this expression is part of the command, and not an expression that can be replaced with EVALUATE(). This is true for

SET FILTER TO &cFilter
INDEX ON &cExpression...
SELECT &cExpression FROM
SCAN FOR &cExpression

and any other FOR clause in any command. Often, macro substitution is used in circumstances, where it is not absolutely necessary, eg:

lcDeleted = SET( "DELETED" )
SET DELETED ON
*...
SET DELETED &lcDeleted

For these commands, you can write:

IF lcDeleted == "OFF"
SET DELETED OFF
ENDIF

to restore the environment.

>4: Filtered indexes, are often used where they are not necessary. The same result can be obtained using SQL without the overhead of having an extra index tag around all the time.

Filtered index don't belong into a table, except for a FOR NOT DELETED() on the primary key (even though there are many discussions going on about this one *g*) and in some rare circumstances, where the filtered index is only used for displaying and sorting data, not to search them, and speed is really an issue that makes it impossible to use a separate index on the filter and a SELECT statement. Please note that this is really the exception!

BUT, filtered indexes are quite usefull on cursors and views when the grid is involved, because they work around the problem of the grid not being Rushmore aware. A filtered index always belongs into the CDX of a view or an IDX index. Be aware that an IDX index causes a lot of problems with transactions and table buffering.

>5: UNIQUE indexes, not only are they misused but they could easily be totally removed from the product without any alteration in capabilities.

The problem with UNIQUE indexes is that they don't form like a primary index or like the DISTINCT clause of a SELECT statement. A unique index works by adding the first entry to the index that VFP finds in the table. If you change that rcord later, like deleting it, this record is removed from the index, but NO other record is added instead. The index epxression seems to be lost and won't be added until the index is built again. Also, an index doesn't enforce uniqueness. If you add a second record with the same value, it simply doesn't appear in the index.

Hence, a unique index can safely only be used as a temporary index. And with that you don't gain anything compared to a SELECT statement.

>6: PUBLIC variables are often used in situations where they are totally not required.

PUBLIC variables are only required in the debugging environment, if you don't issue a READ EVENTS which would keep private variables in scope. Whenever possible, avoid them, because unlike PRIVATE variables, they aren't cleaned up automatically and might cause different reactions of your program on different test runs. As well, don't use them in development tools, because they go out of scope when a CLEAR ALL is issued.

PUBLIC variables had their place in FP 2.x, for example, if you needed to carry over values from one code snippet to the other and for various reasons couldn't create private variables in the setup snippet. But for everything we had PUBLIC variables for in FoxPro 2.x, we have properties now.

Christof
--
Christof
Précédent
Suivant
Répondre
Fil
Voir

Click here to load this message in the networking platform