Wiki Home

Visual FoxPro Useless Features


Namespace: VFP
A Place For The Real Low Points in the VFP Feature Set.

Uselessness changes over time. Are we discussing features that are useless today? -- Mike Yearwood

VFP is a huge product, and it's no surprise that a few of its features never made it to the big time, as it were. This isn't about @ SAY... GET which served us well for years and is now merely deprecated. No, this is a list of things that, were they never in the product, probably nobody would know the difference. They are probably in the product because someone thought, "Hey, this is what developers need, lets put resources into this".

Anyone with planning responsibilities can make this sort of mistake, of course, but here's a list of some of the doozies in Visual FoxPro.

Generally Accepted as Useless
  1. The Active Document baseclass.
  2. The GeneralDataType.

I think, all things considered, this is an amazingly short list....
Here Suggestions and Discussion About Low Points in the VFP Feature Set.

Suggestions for Additions to the Above List
  1. FIND
    While I'd never use FIND in an app, it's actually handy for searching from the Command Window (if you remember to use it).
    LOL! Haven't used FIND in years. Because of faster hardware, etc. LOCATE under Rushmore is so fast unless you are talking extremely large databases. I agree this is totally useless for me at least. -- Randy Jean

    FIND dates back to dBase II and is in there as a leftover. -- Jim BoothOffsite link to http://www.jamesbooth.com

  2. ACCEPT
    I wasn't in at the beginning of Fox. In the late 1980s I was using DBXL, so I may be off the mark here in terms of the role of ACCEPT in Fox. But in DBXL, ACCEPT was the best--and probably the only; it's hard to remember now--way to let a user enter input of indeterminant length. While we have other ways of dealing with this now, we didn't then. So I'd say that ACCEPT doesn't belong on this page. -- Ken Dibble

    Again ACCEPT is leftover from dBase II -- Jim BoothOffsite link to http://www.jamesbooth.com
    Ahhhh DBXL Love it and still use it!!! but to get to the point there was also the GET command used to accept user input to a variable. i.e. @10,10 say 'What is your name:' GET NAME PICTURE '@!' -- Chris Mills
  3. INPUT command
    Once again, I was doing DBXL, not Fox, in the DOS era. But in DBXL, INPUT was very useful for certain specialized purposes, such as password entry. (I had an application that put up an initial splash screen that didn't appear to have any place for user input. However, if a knowledgeable user typed in the appropriate password, INPUT would catch it and start the main program.) So IMO, INPUT was a once-useful feature that doesn't belong on this page. -- Ken Dibble

    Another leftover from dBase II -- Jim BoothOffsite link to http://www.jamesbooth.com

  4. INSERT Actually INSERT AFTER ... INSERT BEFORE are useful to insert rows at a given position in a table with no index.

    Once more a leftover from dBase II used for maintaining the order of a sorted table. -- Jim BoothOffsite link to http://www.jamesbooth.com

  5. Most of the dBASE IV compatibility commands and functions like JOIN and SORT and DEFINE BOX Actually these commands and functions were added into the language when Fox Software was competing for market share with Ashton-Tate. By incorporating a small number of commands and functions that were different between the languages, it made it possible for products like SBT's accounting software series (among many others) to be run under Fox without modification. This increased Fox's sales significantly. -- Ray_Kirk

  6. CursorAdaptors - a too little, too late, not well implemented solution to a problem already solved by the community. Bugs abounded. Better to solve with code.

    I would say better late than never. This object is a RV/LV killer. If you have no local tables [DBFs] that need extended capabilities, you no longer have a need for DBCs. I no longer have to worry about breaking a view definition when the source table structure changes. All I have to do is modify the code for that particular CA. Since I have a class library of CAs for all my Oracle tables, maintainence is a snap. Mark McCasland

    "All I have to do is modify the code for the particular CA" doesn't seem any easier than "all I have to do is fix the particular RV", especially if you have the RV in xCase. As for DBCs- they've been easy to build into apps or since the arrival of CONNSTRING, removing the sharing contentions that certainly used to be a big problem for apps using RVs against secure backends.

    Calling Cursor Adapter a useless feature seems extreme. The CursorAdaptor is excellent for accessing various data from DBF, SQL and/or XML, you can use ODBC or ADO. And because you can create sub-classes of the CursorAdaptor; you can add extra functionality like automatically index the results and/or add properties. I use CA extensively and enjoy the methods like BeforeFill and AfterFill etc, and the functionality it offers over Remote Views.

    Cursor Adapter is useless ???? Someone should have told me this before. I only use Cursor Adapter. In my opinion DBC VIEWS are useless. AFH.

  7. Task Pane
    I disagree. I really like the Task Pane and see a variety of possibilities for making information available.--TamarGranor

    I wish that the Environment Manager could be separated from the Task Pane. It is handy, the rest isn't.

    Actually, the Environment Manager can be separated from the Task Pane. You can find ENVMGR.APP in the VFP home directory. Run it with a parameter of "-m" to add it to your tools menu for quick access. Or, quickly set an environment via the command-line by specifying the name of the environment set, like this:

    DO EnvMgr with "rehab"

    -- Ryan Katri


    I'm mixed on this. Seems to be a VS thing - it's really just a browser in the IDE. I defintely like the XML Web Services pane. A huge improvement over VFP7 Web Service registration, publishing, etc. -- Randy Jean

  8. Anything that has to do with "backward compatibility" for the Macintosh (including the 7 properties in the property sheet that are "Macintosh only"). - William Fields

  9. ZAP
    One should not be able to mark for deletion and physically delete all data with a single command -- Dave Nantais

    I disagree that ZAP is somehow inherently bad. ZAP is the fastest way to empty a table of all records. Unlike DELETE ALL and PACK which has to process the records in the table, ZAP just truncates the table immediately. Like any command that deletes data there is a possibility of doing it in error. But in SQL Server we can DELETE without any WHERE clause and do the same thing that ZAP does. -- Jim BoothOffsite link to http://www.jamesbooth.com

    In fact, SQL Server has a ZAP equivalent - TRUNCATE TABLE. Like ZAP, it's very much faster than actually deleting the records. Mike Lewis.

    One can't, considering we need at least one other command to account for EXCLUSIVE requirement. We all run with SET EXCLUSIVE OFF, right? At least, we certainly should... ref. VFP Rookie Mistakes.-- Steven Black

    I've taken over other people's projects that open tables exclusively AND use the ZAP command; in that environment it is a dangerous command -- Dave Nantais

    I couldn't disagree more. I use this command all the time for pulling test data from production data into the development environment. I may have data changes in development that have not yet deployed. I cannot copy databases and tables and sometimes I want a subset of the production data. Being able to run a routine to zap my local development tables and append a bunch of fresh data is invaluable. -- Pamela Thalacker

    Zap is very useful ... for developers. I don't let the user zap a table, but there can be significant advantage to using zap. Just check out http://foxpro.advisor.com/doc/08218 -- Mike Yearwood

    Steve, SET EXCL ON is a good idea for single-user programs - no unnecessary locking (I havn't tried it, as I don't do single-user programs, but that's what VFP help says). However, ZAP is actually useful - for example, if you want to requery the data in a cursor which a grid points to, ZAP is invaluable, as you cannot PACK a cursor. There are other ways around this, of course, but ZAP and APPEND FROM seem the best to me. ZAP is also very useful in a development environment. -- Peter Crabtree
  10. Intrinsic macro expansion when assigning a string literal to a memvar. Somebody told me onetime that this was a feature of VFP so I think this would apply. I’m still waiting for somebody to explain the usefulness of this “Feature”.
    LOCAL Company, ChildrenTVShow
    Company = "Wierd Behavior"
    ChildrenTVShow = "Puff'n'Stuff&Company"
    ?ChildrenTVShow && displays "Puff'n'StuffWierd Behavior"

    This is simply the result of the precedence of operations, macro expansion is processed before the assignment or quotes are processed. I don't see anything wrong or right about this and it is only weird behavior if you expected something else to happen. Once you know the behavior it is very easy to deal with. I have the habit of always breaking &'s up in string asignments ...

    ChildrenTVShow = "Puff'n'Stuff&" + "Company"
    -- Jim BoothOffsite link to http://www.jamesbooth.com

    Replace the quotation marks in your string assignment with square brackets. The macro substitution will no longer occur and you'll see your string with the ampersand correctly.
    Fred Taylor

    Square Brackets? Can we get a snippet please? Tim Hustler

    Seriously Fred, did you test this solution before you wrote your comment? I tested your solution and the results are the same, expansion is being performed.


    I've used Macro Substitution with great success when accessing objects on the fly.

    Suppose I have a container with 20 or so textboxes in it, all imaginatively called "txtTimzTextBox1", "txtTimzTextBox2" and so on. I could recursively set a string thus ;

    lcObjectString = "Thisform.TimzContainer.txtTimzTextBox" + Alltrim(Str(lnTimzIndexCounter))

    then macro it to get my object out.

    loTimzCurrentObject = &lcObjectString

    then, loTimzCurrentObject is a reference to the object in question, containing all the properties of the textbox. With VFP's lack of Strong-Typing, you can declare whatever variable you like and set it to whatever content you feel like. And if you change your mind, just set it to something else, VFP doesn't care ;¬)

    However, Macro Substitution makes the code very difficult to understand if you weren't in on the inception stage, as I'm now finding out after looking at a colleague's Macro-Ridden Spaghetti Code. It can help but can hinder later on so be warned.

    You could probably just use &lcObjectString.., though I find the double-dot syntax even trickier to read

    Tim Hustler

    Tim, I could be wrong but I don't think you understand my concerns with my original "useless feature" complaint. I'm not saying macro expanding is a bad thing but macro expanding when doing an assingment. Look at my code again, a string literal has an Ampersand in it. When this string literal gets assigned to the memvar an expansion happens intrinsicly. This is the useless feature I'm speaking of not the macro expansion operator.

    I think I see what you mean. you actually wanted the string "Huff 'n' Puff&Company". Just another case for naming conventions. A local char variable would be pre-pended lc so Company would be lcCompany. Though, some schools of thought would leave that out and, in the case of Macro Subtutition, would cause undesirable effects. I do like JoKi's solution below however Tim Hustler

    There is a use for this, though it's in conjunction with a limitation of another object so doens't really count :¬(

    When using the AddTableSchema() function of the XMLAdapter, the first parameter is the name of the table you will be adding.

    loXMLAdapter.AddTableSchema("TimzTable") works just fine

    However, the following causes errors when you use the ToXML function, as the adapter is unable to locate the Alias within itself (?!?!)

    lcTableName = "TimzTable"
    loXMLAdpater.AddTableSchema(lcTableName)


    Which makes it a nightmare for dynamic addition of tables as all tablenames seem to be hard-wired. This is where macro-substitution saves the day as

    lcTablename = "TimzTable"
    loXMLAdapter.AddTableSchema("&lcTableName")


    works just fine. bit hacky tho IMO. Anyone know if this is fixed in vfp9? Tim Hustler

    While I agree that its unusual, my take is that it's just one of those things, sort of like an EOF() condition in the active work area causing updating in other areas to do nothing.
    In fact I see it as a potentially USEFUL feature, once you know about it < s >. And after all, your example is mis-typed to start with, putting the ampersand right up against both "Stuff" and "Company". Had you put the spaces in, as in real life, nothing 'unusual' would occur. -- Jim Nelson

    The few times I've seen embedded macros, it was for this sort of thing: "&lcFirstName &lcLastName" yielding "Jim Nelson". This would be better, faster and cleaner done as m.lcFirstName + " " + m.lcLastName. Macro-subbing is far more useful for adding parts to commands that access sets of records. -- Mike Yearwood

    I guess that just knowing your tool, regardless of the quirky behavior, is the key to writing good, bullet proof code. The fact is this is a string literal asignment,, period. This behavior in any other programing language would be considered a unusual and pointless feature.

    Yes, know your tool is the key. But I do take issue with your last statement. Firstly, I too, based on the other languages I had done, always considered a literal to be a literal, meaning that it was an unlabeled string never to be changed in any way. But in fact the only place I've come across "macro substitution" is in xBase. What I'm trying to say is that neither "unusual" nor "pointless" really apply for other languages. *IF* some other language did do it, then it would certainly not be either unusual or pointless (else why would it do it in the first place?) --JimNelson

    Why in the first place? You tell me. I thought that was the point of this category, "useless features". As far as I'm concerned I'm still haven't seen a good use of this feature. Mike had an example but there is a better solution (More readable and faster) as he pointed out. Also, why in the first place, alot of bright people thought of something that seemed like it was a good idea at first but later deemed not the case. I think this is one of them. Just My opinion.

    What about using the Evaluate() function instead of macro substitution?
    loTimzCurrentObject = Evaluate("Thisform.TimzContainer.txtTimzTextBox" + Alltrim(Str(lnTimzIndexCounter)))
    Personally I don't like macro substitution in any way and try to avoid it in every situation. -- JoKi

    I believe that the Macro substitution in a string literal was to enable things like:
    lcTableName = 'My Long Table Name' USE "&lcTableName" ALIAS MyTable
    Granted, NameExpressions are a better way of doing this:
    lcTableName = 'My Long Table Name' USE (lcTableName) ALIAS MyTable
    ..but I don't know what version they were introduced in. -- ?wgcs

    As far as other languages vs VFP, PHP does basically this same thing:
    $variable = "test";
    echo "This is a $variable";
    // Will output:
    // This is a test
    


    -- Peter Crabtree

  11. The "Cancel program?" dialog that comes up when you choose "Fix" from the Debug menu. Anyone ever pressed "No"? - Lauren Clarke
    Just did! The Fix option does not always work, like when the code you're trying to fix is in a superclass of something on the current form. In those cases, you'll have to remember the method name so you can open it. I had clicked Fix, but the method name was too long for the Combo Box, so I had to click Cancel. -- Mike Yearwood

  12. The spinner control in the Edit~Go to Line... dialog.
  13. Support for square brackets and parentheses for functions and arrays. I just reviewed some old code that used brackets for procedures and parentheses for arrays. What a nightmare. Please someone explain how this was once useful. -- Tod McKenna
    Why???? Surely it's a "nightmare" only because you make it such. Especially when you imply, above, that the code was consistent in its deployment of each. And even if it wasn't, letting something like that bother you so only makes the job harder. Why sweat the really small stuff? -- Jim Nelson

    Calling it a nightmare is certainly an overstatement: It was more of an annoyance. Also, it wasn't nearly as consistent as I made it sound. Regardless, small stuff or not, I still don't see how this can be considered useful. On another note, this is one of the only things I have to complain about. VFP doesn't give me many other outlets :-s -- Tod McKenna

  14. The Control class. Lets you put something inside a container where nothing can reach it. Ever. In theory, this would allow you to work in a more OO way by only exposing limited behaviour, as opposed to the entire PEM. However, VFP's odd object model which makes proper encapsulation difficult (frequently requiring you to break it) renders this entirely useless.
    I have to disagree with the Control class being useless. It is very useful for building controls where you want the component pieces hidden from any view or access other than through the properties and methods of the control you are building. --JimBooth

    Do you say that from actual experience of doing so? My experience (albeit short) is that there are some circumstances where reaching into an object's properties is unavoidable (e.g. when building a MESSAGEBOX() replacement), because the VFP object model sometimes prevents you from assigning an object enough responsibility to do its job completely. For instance, in the case of a replacement for MESSAGEBOX(), you end up having to pass control between the object and its caller, and the caller ends up having to do the Init(), Show(), Ask(), Get(), Release(), etc. whereas a sane object model will let you just get the object to DoSomething(), and it takes care of all the rest. This cannot be done with things as they are (e.g. having one reference to the object that will capture the return value, having the one method to both do the return and call Release(), etc.). YourMileageMayVary.

    The problem that this poster is having is due to using the release() method. An object should not contain the logic dictating its own destruction, especially since it can't contain the logic governing its creation. Release() violates this principal. Assuming that the poster has created a form, the oopy way to do this is do form name ... linked. This way the object will persist in the method of the creating object which can then examine the new messagebox's properties for any information it needs. After it's done, it nulls out the reference and the form will disappear. --LewSchwartz




Category VFP Language - Key Words Category VFP Controls
( Topic last updated: 2008.12.09 02:07:03 PM )