Go Back  Xtreme Visual Basic Talk > Legacy Visual Basic (VB 4/5/6) > Knowledge Base > Tutors' Corner > Standards and Practices


Reply
 
Thread Tools Display Modes
  #1  
Old 06-01-2002, 01:15 AM
loquin's Avatar
loquin loquin is offline
Google Hound

Retired Moderator
* Guru *
 
Join Date: Nov 2001
Location: Arizona, USA
Posts: 12,402
Post Standards and Practices


Standards and Practices
Table of Contents
Either select the individual lesson link for a specific tutorial, or just scroll down the page.
Note: Several general-purpose tutorials, listed below, which tend to deal with topics that are not VB specific, have been moved to a separate tutorial. You can access this thread via this link, or jump directly to the individual posts listed below.
.
__________________
Lou
"I have my standards. They may be low, but I have them!" ~ Bette Middler
"It's a book about a Spanish guy called Manual. You should read it." ~ Dilbert
"To understand recursion, you must first understand recursion." ~ unknown

Last edited by loquin; 05-09-2007 at 09:09 PM.
Reply With Quote
  #2  
Old 06-01-2002, 01:15 AM
loquin's Avatar
loquin loquin is offline
Google Hound

Retired Moderator
* Guru *
 
Join Date: Nov 2001
Location: Arizona, USA
Posts: 12,402
Post Standards and Practices

In the Extreme Visual Basic Forum Mission Statement, it states, "This Forum exists to promote the personal and professional development of its members." It goes on to say "we promote programming skills by exchanging code, knowledge, and ideas."

In most of the cases here at the forum, members ask and answer questions pertaining to specific problems or issues they are having in applying Visual Basic. That's great - it addresses, to a large extent, the promotion of programming skills by the exchange of code and knowledge, and to a lesser extent, exchanging ideas. In my opinion though, one of the important programming knowledge areas that is not addressed often enough here is the concept of Programming Standards and Practices.

"#$%*@^!," you're thinking. "Not someone else telling me how to write my code." As it turns out, there are generally pretty good reasons for most of the suggestions that have been made in this regard. In a lot of cases though, the person making the suggestion may have not done a thorough job of explaining just what those reasons are, and why the suggestion was made. What are the reasons you would want to apply this suggestion? Are there ever reasons for not doing something this way? If I don't do this, what are the ramifications?

Visual Basic programmers (and programmers as a whole) have developed sets of guidelines, standards, and practices over the years. These concepts are good rules to generally apply when you develop an application. They don't have to be applied in all instances though. In some instances, trade-offs are involved. Style versus Performance. Performance versus Maintainability. Your goal, as a programmer, should be to learn when to apply, and even more importantly, when not to apply these guidelines. If you make a conscious decision to not follow a standard, and have thought through the ramifications, so be it. You've done your homework.

In order for you follow the "rules of the road" though, it helps to have a road map. In other words, you need to know what the rules are, and why they are there in the first place. It's my intention to write a series of follow up mini-tutorials specifically dealing with many of the common programming standards and practices. I'm planning on releasing a new session topic, on average, every few weeks. I've polled the other forum leaders for topic suggestions, and as usual, they haven't been shy in putting forward ideas. If you have a specific topic that you think should be discussed, just shoot me a private message with your idea.

Microsoft has also published a set of standards in MSDN that are useful as well.
__________________
Lou
"I have my standards. They may be low, but I have them!" ~ Bette Middler
"It's a book about a Spanish guy called Manual. You should read it." ~ Dilbert
"To understand recursion, you must first understand recursion." ~ unknown

Last edited by loquin; 08-13-2005 at 08:23 AM.
Reply With Quote
  #3  
Old 06-01-2002, 04:22 AM
loquin's Avatar
loquin loquin is offline
Google Hound

Retired Moderator
* Guru *
 
Join Date: Nov 2001
Location: Arizona, USA
Posts: 12,402
Post What's in a Name?

So, why the bother with naming conventions anyway? After all, over 400 years ago, Shakespeare wrote in Romeo and Juliet, "What's in a name? That which we call a rose, by any other name would smell as sweet."

Well, in Will's story, everyone involved knew that Romeo was discussing, (metaphorically, of course,) his lover, Juliet. That's not always the case in the programming arena though. If you were looking at a section of someone else's code and saw a variable named "Rose", what type of variable is it? Does it refer to a color, and should therefore be a long datatype? Or, maybe it is the name of a young lady, and should therefore be considered a string. Or, what about a type of flower, which could have a User Defined Type (UDT) containing common name, latin name, germination period, etc.

To help programmers with this problem, Microsoft programmer Charles Simonyi developed a methodology or naming convention. and detailed the conditions for its use. His naming convention became known as the Hungarian naming convention, due to the fact that the name Simonyi (as well Charles himself) is of Hungarian descent.

Basing his work on that of Simonyi, Gregory Reddick developed a set of conventions for VBA, most of which are appropriate for Visual Basic.

In both Simonyi's and Reddick's standards, the basic convention is to identify a variable name as a Type and a Tag. The Type, always in lower case, is generally a three-character prefix code that identifies the type of data (or an object type) stored within the variable. For example, a prefix of int would identify the variable as an integer; str would represent a string, and txt a textbox. The Tag portion of a variable name represents the data contained within the variable and always begins with a capital letter. LastName, Title, or PhoneNumber, for instance, could represent the Tag. Combining the two fields could result in variable names such as intKeyField, strLastName or txtPhoneNumber, for instance. Microsoft has developed and published a couple of lists of common suggested prefixes as well. The variable and constant list is avaliable here. In addition, their suggested list of objects is here.

Simonyi and Reddick both identify further modifications or enhancements to this base convention, but I won't discuss it further here. Follow the links to their respective naming conventions, above, if you would like to read a more complete discussion of their ideas.

Note that it is not always necessary to apply strict naming conventions in your programs. Simonyi mentions this and discusses those instances. They typically come up when you have written small subroutines or functions that contain a few local variables. In this instance, the scope of usage is small, and the number of variables is also small. Since virtually any programmer should be able to follow and understand what the function is doing after a few seconds study, no further clarification is needed. An example of this is the common use of N or I as loop counters in short Functions or Subs.

So far we've talked about what the Hungarian naming convention is, but very little about WHY we might want to apply it. Essentially, as applications become more complex, the sheer number of variables and constants used within it grow, in both number, and often in complexity. It becomes difficult for the average programmer to keep track of all the variables present in the code. Applying consistent naming conventions like Hungarian notation in your project WILL help you be more efficient in your programming. Just by looking at a variable, at a glance you can tell the type of variable that it holds, and a good idea of what sort of information it holds.

What is more, not only can you tell this information at a glance, anyone who works on the code with you, or reviews your work, or who maintains the code can as well.

"I don't have any other people who are working with me, and I know my own code, so I don't think this naming junk will help me," you may be thinking. Well, while that may be so, what about when you open that program you wrote two years ago, and haven't had to look at since but someone (maybe you) uncovered a subtle bug in it. You'll have a real learning curve on your hands. Even though you wrote it, it WILL take you some time to understand what you wrote earlier. I've been there, and done that. Applying a consistent naming process will do nothing but help you.

Even though you currently might work alone, you may need to work with others on a large project in the future. When multiple programmers are involved in working on a project, naming conventions become even more critical. You will be reviewing the other programmer's code, and they will be reviewing yours.

"Since I'm not working with anything very large yet, why should I start trying something new? I can pick it up when I'll need it on a larger project" A few weeks ago, I had the opportunity to walk through the Band Practice Room at my daughter's school. A large sign on the wall reminds the music students that "Practice Makes Permanent, only Perfect Practice Makes Perfect." I really feel that this applies in our situation also. I've noticed that as I have made concerted efforts over the years to improve and to be more consistent in my programming style, it has become almost second nature to do so. It has gotten to the point that I rarely have to even think about it any more.

A common error for beginners (and sometimes for those more experienced ) is to give a variable the same name as a standard function/sub name. This is a poor practice for two reasons. First, it is extremely confusing when trying to troubleshoot the application. Secondly, you lose the function or sub that you have renamed. It has been redefined, and the original function isn't available for use. So, for instance, if I were to name a variable Sqr, I couldn't use the square root function in my code. By following a standardized naming convention, you are unlikely to name one of your variables with the same name as an existing sub or function.

One last point in favor of learning, and more importantly, applying consistent naming conventions in your code is a very pragmatic one; I, as well as many senior programmers and analysts in the industry, are actively involved in the selection of new programmers at our places of employment. Typically, I get the opportunity to interview all the folks who are applying for a programming position in my (IT) department. During these interviews, I have a set of questions that I will ask all the applicants, and I will ask them to write a small program for me which will perform a simple task - maybe display data from an Access table on a form. When I look at their code, naming conventions are one of the things that I look for, and I know that I'm NOT the only one who does this. It just makes good business sense. After all, what if I have to pick up a project for one of my co-workers when they quit, or have a baby, or break their leg, or any of a whole number of possibilities?

So, after all, what IS in a name?
__________________
Lou
"I have my standards. They may be low, but I have them!" ~ Bette Middler
"It's a book about a Spanish guy called Manual. You should read it." ~ Dilbert
"To understand recursion, you must first understand recursion." ~ unknown

Last edited by loquin; 10-21-2004 at 05:27 PM.
Reply With Quote
  #4  
Old 06-01-2002, 03:04 PM
loquin's Avatar
loquin loquin is offline
Google Hound

Retired Moderator
* Guru *
 
Join Date: Nov 2001
Location: Arizona, USA
Posts: 12,402
Post Abracadabra. Alakazam!

A 'Magic Number' is a number (other than 0 or 1) that is used in your code. As a programmer, you should avoid their use. There are several reasons for not using magic numbers in your code. First, and probably foremost, is that using them will make your code harder to understand and more difficult to maintain and troubleshoot.

Consider the following example: You will be printing a report directly to the printer on 8.5 x 11 inch paper, and you want to ensure that there are half-inch margins on your report. You know that like the form units, the printer units are in Twips, which are scaled such that 1 inch = 1440 Twips. So, you write a subroutine to print the header of your report. The Sub will accept a Title line (String) a user name (String), a page number (Integer) and a label. (The label is used to provide font formatting for your report; it is not visible during runtime.)
Code:
Private Sub PrintHeader (strTitle as String, strUserName as String, _ intPageNumber as Integer, lblFormat as Label) ' This sub will print the header for the report. ' First, set the Printer Font Printer.Font = lblFormat.Font ' Set initial X and Y positions Printer.CurrentY = 0.5 * 1440 ' ½ Inch Margin, in Twips Printer.CurrentX = 0.5 * 1440 Printer.Print strUserName; ' Set Title Position in the Middle of the page Printer.CurrentX = ((8.5 / 2 ) * 1440) – _ Printer.TextWidth(strTitle) / 2 Printer.Print strTitle; ' Now Set the position of the Page Number Printer.CurrentX = ((8.5 - 0.5) * 1440) – _ Printer.TextWidth(“Page “ & cStr(intPageNumber)) Printer.Print “Page “ & cStr(intPageNumber) End Sub
Looking at this subroutine, you can see that there are several magic numbers in it. First, there is the 0.5 inch margin, the Number of Twips per inch, and the paper width itself. This Sub will work just fine. But, only for the conditions that you have defined. If you change any of these conditions, you will have to go into the code and change them. In several locations, each. A better approach, in this instance, would be to add constants to your code, and refer to these constants in your Sub. This way, when you change the Margin, or you get a ream of A4 paper, you will only have to change the constant in one location. Take a look at the following changes:
Code:
Const sngMargin as Single = 0.5 ' Report Margin, in Inches Const intTwipsPerInch as Integer = 1440 ' Twips conversion constant Const sngPaperWidth as Single = 8.5 ' Width of Paper, in Inches Const sngTwipsMargin as Single = sngMargin * intTwipsPerInch Const sngPWidthTwips as single = sngPaperWidth * intTwipsPerInch Private Sub PrintHeader (strTitle as String, strUserName as String, _ intPageNumber as Integer, lblFormat as Label) ' This sub will print the header for the report. ' First, set the Printer Font Printer.Font = lblFormat.Font ' Set initial X and Y positions Printer.CurrentY = sngTwipsMargin Printer.CurrentX = sngTwipsMargin Printer.Print strUserName; ' Set Title Position in the Middle of the page Printer.CurrentX = (sngPWidthTwips – Printer.TextWidth(strTitle) / 2 Printer.Print strTitle; ' Now Set the position of the Page Number Printer.CurrentX = sngPWidthTwips – sngTwipsMargin - _ Printer.TextWidth(“Page “ & cStr(intPageNumber)) Printer.Print “Page “ & cStr(intPageNumber) End Sub
Now, if you need to change the margins or paper width, you only need to do so in ONE spot in the code. No muss, No fuss. And, although it's easy to spot all the locations in this simple example, it is still possible to miss one, or to mistype it. When the code gets larger, it just gets easier and easier to screw up and miss one. (And I speak from experience here... ) Note that when you when you add a constant, you only need to comment it well in just one location also. This approach will make your code both easier to read AND easier to maintain.

Also, look at the 4th and 5th constants: They are calculated constants, derived from the earlier constants.

Of course, the instance above is somewhat contrived. You can eliminate one of the dependencies, above, by removing all the references to the Paper Size (In Twips OR inches) and, instead, use the object property Printer.Width. The Printer.Width property contains the current printer width. It automatically changes if the printer is set to Landscape mode, or if you change the paper size. Also, in this case, you could combine the use of the title and the label into one parameter. I kept them separate for clarity.

In addition, please note the placement of the constants. They were placed outside the Sub. Since this tutorial is focused on the use of constants rather than the scope of constants and variables (a topic for a later tutorial,) I won't go into any real detail here, but the reasoning in this is to allow other subs or functions on this form to use these same constants as well.
__________________
Lou
"I have my standards. They may be low, but I have them!" ~ Bette Middler
"It's a book about a Spanish guy called Manual. You should read it." ~ Dilbert
"To understand recursion, you must first understand recursion." ~ unknown

Last edited by Squirm; 05-01-2003 at 06:36 AM.
Reply With Quote
  #5  
Old 06-03-2002, 03:34 PM
loquin's Avatar
loquin loquin is offline
Google Hound

Retired Moderator
* Guru *
 
Join Date: Nov 2001
Location: Arizona, USA
Posts: 12,402
Post Would you care to Comment on that???

“Well what do you know here is another darn article on coding and standards why would anyone want to bother with that just read my code and you can see what is going on and understand it easily my friend john said that he can read my code just fine so im not even going to read this one”

If you can read my little parody as easily as you could read a paragraph with spacing, capitalization, and punctuation, then you are in the minority. e. e. cummings pioneered throwing away all the capital letters, which may be fine in regards to poetry. However, he still used punctuation and spacing to help achieve dramatic impact. Our goals as programmers shouldn't include producing “dramatic' code, however…

Seriously though; what should our code look like? Everyone you talk to has a little different interpretation of good programming style, however, there are some common threads.

Indentation
Indentation can be extremely useful when trying to understand code; essentially, the code within a conditional statement (If-Then-Else or Select-Case) or inside a loop structure (For, Do) is indented, making code easier to comprehend. Consider the following two code examples, for instance:
Code:
Private Sub cmdNext_Click() On Error GoTo GoNextError ' move if not at end If Not adoPrimaryRS.EOF Then adoPrimaryRS.MoveNext If adoPrimaryRS.EOF And adoPrimaryRS.RecordCount > 0 Then Beep 'moved off the end so go back adoPrimaryRS.MoveLast End If 'show the current record mbDataChanged = False Exit Sub GoNextError: MsgBox Err.Description End Sub Private Sub cmdNext_Click() On Error GoTo GoNextError ' move if not at end If Not adoPrimaryRS.EOF Then adoPrimaryRS.MoveNext If adoPrimaryRS.EOF And adoPrimaryRS.RecordCount > 0 Then Beep 'moved off the end so go back adoPrimaryRS.MoveLast End If 'show the current record mbDataChanged = False Exit Sub GoNextError: MsgBox Err.Description End Sub
Because of the indenting levels in the first example, it is much easier to read than the second. Microsoft has actually performed some studies of indenting, and reported that indent levels of 3 or 4 characters were the easiest to read and comprehend.

FYI, An outstanding free VB Add-on is available at VBCity.com: it's called PrettyCode.Print. When printing, this add-on will indent and format your code (for the printout only - it won't touch the source,) add page headers/footers, and add begin-end connection lines, which can really benefit you when trying uncover logic errors in your code.

White Space
White space is just what it sounds like - additional spacing between lines of code. It's certainly not needed for the program to run properly, and it will take extra space on your screen, causing you to scroll more than you otherwise would. The basic idea is that separate concepts should be separated by an extra line or two. When comparing writing code to writing a story, think about how a book is laid out. It has sentences, paragraphs, and chapters. Your program will (or should) have the same sort of structure. Functions and Procedures will correlate to chapters; Statements should correspond to sentences. In your code, if a portion of the code has a common thread; perhaps you are setting printer font properties, for instance, you should add an extra, blank line before and after this code. Someone else who is looking at your code can easily see that all the code in this 'paragraph' deals with a common concept. It helps in the visualization and comprehension of your program.

Let's look at the same piece of code as before, both with and without the white space.
Code:
Private Sub cmdNext_Click() On Error GoTo GoNextError ' ' move if not at end If Not adoPrimaryRS.EOF Then adoPrimaryRS.MoveNext ' If adoPrimaryRS.EOF And adoPrimaryRS.RecordCount > 0 Then Beep 'moved off the end so go back adoPrimaryRS.MoveLast End If ' 'show the current record mbDataChanged = False ' Exit Sub ' GoNextError: MsgBox Err.Description ' End Sub Private Sub cmdNext_Click() On Error GoTo GoNextError ' move if not at end If Not adoPrimaryRS.EOF Then adoPrimaryRS.MoveNext If adoPrimaryRS.EOF And adoPrimaryRS.RecordCount > 0 Then Beep 'moved off the end so go back adoPrimaryRS.MoveLast End If 'show the current record mbDataChanged = False Exit Sub GoNextError: MsgBox Err.Description End Sub
It's amazing how much easier it is to read code that has sufficient white space in it to separate the concepts.

Comments
Comments are an absolutely essential part of every program. When reading a textbook in college, I usually would highlight the key concepts in the text with a neon highlighter, and jot notes in the margins. Most college textbooks are laid out with extra-wide margins for this very purpose. In fact, at Half.com, an ebay sponsored used book website, I noticed that textbooks with “heavily commented margins” were selling for more than the “Like New” versions of the same book. What about that! Comments really ARE worth something!

The programming concept is the same. In your programs, the key concepts should have a comment that explains what you are doing, and sometimes, if the concept is abstract or obscure, why you are doing it. It is certainly possible to overdo commenting, and to insert way too many of them. However, this is usually not a problem. If in doubt, ask yourself if a new programmer in your department would benefit from a comment in this location. (Or if you are the new programmer, ask yourself “Would it benefit me to have this here when I have to look at this code again in 6 months?” )

Commenting is the one major area that, as we gain experience and skill in our profession, we actually tend to get worse at doing. “There's nothing new in THIS code, I don't need a comment here…” you may say to yourself. Well, as I said earlier, try to put yourself in the position of someone fresh out of college. Would a few words in a comment help explain what you're doing?

I once knew a programmer who had written a large, elaborate COBOL program for our accounting department. This person had created an application that worked wonderfully well. However, the code was poorly commented, and very complex. He had essentially created great job security for himself. There was, however, one drawback. Because the code was so complex and difficult to understand, the author could never be promoted! He ended up being pigeon-holed into his current position. Then, when the old mainframe was retired in favor of a new, Oracle-based accounting system, he was laid off...


Associated with all three concepts that I've discussed in this article, is the multi-statement line. In order to interactively run multiple statements at once in the debug window, Microsoft included the ability to enter multiple statements on one line, separated by the colon ( “:” ) An example of this might be a loop to print all the values in an array :
Code:
Dim L: For L = 0 to Ubound(intArray)-1: Debug.Print L, intArray(L): Next
This type of code, while it could be used in an application, violates all three common style guidelines at once! It's not indented, it has zero white space, and has no comments. Unless there is an awfully good over-riding reason to program in this style, don't, repeat, don't do it.

The last common style point that I wanted to discuss concerns the length of a sub or function. Under normal conditions, you should try to limit the total length of a sub to a screen or two in length. By breaking up long sections of code into smaller subs or functions, not only do you make the individual portions of code easier to understand, you act to modularize your code. Once you have a module working properly, you shouldn't have to revisit it. This should tend to make you code more robust, and more easily maintained. Obviously, there will be some instances where you choose to have a sub be longer than the recommended length. This could be especially true in the case of a custom report, where you may be printing many field values. However, even in these instances, it is often possible to greatly reduce the size of your code by judicious use of loop structures and arrays.

Remember, one of your main goals as a programmer is not only to generate code that works, but to generate code that is maintainable - and this means code that is easily read and comprehended by the average programmer. The easiest way to ensure this is to make sure that your code is consistently indented, that it has enough white space to isolate the ideas and concepts, and that it is well commented.
__________________
Lou
"I have my standards. They may be low, but I have them!" ~ Bette Middler
"It's a book about a Spanish guy called Manual. You should read it." ~ Dilbert
"To understand recursion, you must first understand recursion." ~ unknown

Last edited by loquin; 05-26-2005 at 11:26 AM.
Reply With Quote
  #6  
Old 06-09-2002, 01:15 AM
loquin's Avatar
loquin loquin is offline
Google Hound

Retired Moderator
* Guru *
 
Join Date: Nov 2001
Location: Arizona, USA
Posts: 12,402
Post Scope that!

"A place for everything and everything in it's place." When growing up, that's what my Mother would tell me, as with a firm grasp on my ear, she marched me towards my room. Of course, Mum was talking about the state of my closet, and not about programming. Those words DO have application in the world of programming though.

Of course, we have a different term for that idea. It's called 'Scope.' So, that being said, what do we mean by the word scope, anyway?

Essentially, scope defines where a variable will be used. Visual Basic allows three levels of scope. Procedure level, or Local scope is confined to a Sub or Function. Form level scope is confined to a given form (or module.) And Global scope is defined as anyplace within a project.

There is only one simple guideline to follow in regards to scope. You shouldn't define a variable so that it can be accessed outside the local programming area unless there is a good reason for doing so.

Well, that's simple enough. But why? What is the basic reasoning behind such a rule? The answer to this question is a pragmatic one. By doing so, we all will have less opportunity to screw up. Essentially, it's awfully easy to be working in a procedure and inadvertently use a variable name that you intended to be used in another place entirely. If you defined the variable scope too broadly, VB won't complain. It assumes that you know what you are doing. (That's a scary thought, isn't it… ) Then, unexpected things can happen, results that are sometimes very hard to find a reason for. And, to troubleshoot...

As I mentioned earlier, Visual Basic's three levels of scope are Procedure level, Form Level, and Global. Details of the three levels follow.

Procedure Level Scope: The variable is said to be Local. It can't be accessed outside the procedure. And it is safe. You know that your variable CAN'T be changed from the outside. This isolation of the local properties enables you to make your code modular: Write a small portion of the main code. Test It. Then, forget it. The use of procedure level variables is efficient from a memory usage viewpoint also. When the procedure runs, memory is allocated at that time, and this memory is released when the procedure finishes. If you have to have a Sub or Function level variable which needs to stay present in memory between calls to the procedure, you may declare it using the Static keyword:
Code:
Static intWinSockPort as Integer
In this manner, the variable remains local, but will stay in memory (and retain it's value) between procedure calls.

Form (Module) Level Scope: There are two types: Public or Private. The Private Form level variable is available by all the functions or subs within the form, but is not available outside the form. This is useful when defining a variable that pertains to the entire form. A Public form level variable is available to all functions and Subs inside the form, and is also available outside the form by referencing the form and the variable name. Essentially, a public form level variable appears as a new property of the form. For example, assume that you want to create a simple form called frmUserInput to obtain user input. You would create the form, and at the top of the form code, add a public variable called strFormResponse. From another form, you would then access the new variable like this:
Code:
UserResponse = frmUserInput.strFormResponse
Of course, you could also write to the variable in the same manner. However, since you specifically have to refer to the form name as well as the variable, the risk of accidental data corruption is small. Since data transfer between forms is a common requirement, I've attached a sample project which provides an example of this.

Global Scope: In your module code in a project, you may also define public and private variables and constants. In a similar manner to the form level variables, those defined as Private in a module are only accessible from subs and functions within the specific module. If they are defined as Public, however, they may be accessed from any code in any module or form. (The old convention for the public module variable is "Global." The global keyword has been made obsolete by the Public keyword, and is only included in VB 6 for backwards compatibility with older code.

Keep in mind that a public module variable is dangerous to use; any code, anywhere in the project may read or write to this variable. And, since the variable is not associated with a form, it is referred to by name; just as if it were a local variable. Even IF you are using the recommended "Option Explicit" setting you may accidentally refer to a public module variable. Another disadvantage of public module level variables is that memory is assigned to them when your application loads, and this memory is not relinquished until the program shuts down.

A word about "Option Explicit". Use it. Always use it. What it does for you is simple. It won't let you compile or run a program if you haven't explicitly defined all your variables. In other words, there must be a Dim VariableName as VariableType for every variable in your code. If you don't use option explicit, VB will implicitly define a variable if you don't. And, there's a couple of problems with this. First, VB will pick a variant type, which is compatible with many different variables. However, a variant is probably the largest and most inefficient of all variable types, which may have performance implications. Variants also sometimes won't work for your purposes. The second main problem with VB defining a new variable for you is that often, the reason for a new variable is not that you don't have one, it's that you mis-typed the correct variable name. This means that either your new variable or your old variable will be "orphaned," which can lead to logic errors in your program that can be hard to spot. Visual Basic even has an option setting so that the words "Option Explicit" will automatically be added to each and every new form as you create them. Just go to the Tools, Options menu and select the check box labeled "Require Variable Declaration."

In spite of the dangers involved with using public module level variables, in some instances, especially with constants, they can be invaluable. I'm NOT saying "Don't use public level variables," I'm suggesting that you use them carefully.

Essentially, the golden rule in regards to scope is "Always define your variables at a scope level no higher than is necessary for proper function." By doing so, you can ensure that your code remains as modular as possible, and will not have its operation inadvertently changed by external code.

So, just remember, as I'm figuratively holding on to your ear, "It's for your own good, and it hurts me more than it hurts you, and…"
Attached Files
File Type: zip ShowDataXfer.zip (2.6 KB, 168 views)
__________________
Lou
"I have my standards. They may be low, but I have them!" ~ Bette Middler
"It's a book about a Spanish guy called Manual. You should read it." ~ Dilbert
"To understand recursion, you must first understand recursion." ~ unknown

Last edited by loquin; 11-08-2007 at 11:16 AM. Reason: Add zip attachment, and reference to same.
Reply With Quote
  #7  
Old 03-02-2003, 10:51 PM
loquin's Avatar
loquin loquin is offline
Google Hound

Retired Moderator
* Guru *
 
Join Date: Nov 2001
Location: Arizona, USA
Posts: 12,402
Default Loopy

Here I am, back once more, talking about standards yet again. Actually, this is somewhat ironic, since the topic of this installment is looping...

In almost any app, the computer is programmed to perform one or more activities over and over. This, after all, is one of the tasks where a computer works very well. The process of repetitively processing the same chunk of code is known as looping. Looping can greatly improve the efficiency of your coding. Suppose that you have an array of 5000 integers that needs to be initialized to -1. You could add 5000 lines of code to perform this action…

However, this would be very tedious, and would result in a large program segment that does little. A better approach would be to use a loop to initialize the array. The power of the loop structure goes hand-in-hand with another feature of most computer programming languages - the array. An array is just a method of notation that groups identical variable types under a common name. Visual Basic extends the concept of variable arrays to also include arrays of controls on your form. This allows for efficiency improvements in accessing numbers of identical control types.

Visual Basic, Version 6, offers three basic types of looping structures. These types are the For-Next Loop, the For-Each Loop and the Do Loop. I’ll spend some time discussing each of these types of looping structure.

For-Next Loop

The For-Next loop is best suited for applications where you know, or will know, the number of iterations the code is to perform. For example, suppose that you need to inspect every character in a string to see if it is numeric (0-9), and if so, copy it to another string. Since you can know the length of the string, and therefore the number of characters to check, the loop for this function could be:

Code:
Dim N as Integer Dim strNum as String Dim strTest as String … strTest = Text1.Text For N = 1 to Len (strTest) If Mid$(strTest, N, 1) >= "0" And Mid$(strTest, N, 1) <= "9" Then strNum = strNum & Mid$(strTest,N,1) End If Next N
A few comments about the For-Next loop are in order.

The For loop will examine the loop counter at the beginning of each iteration to see if the counter has exceeded the test value. If a floating point type variable is used, the For-Next loop MAY exit before you think it should, or run an “extra” iteration. This is due to potential precision error in a floating point type variable. A Single or Double approximates the value of the number it represents, generally quite closely, but usually not exactly. This means that even if you THINK the value of the counter should be 0.10, it might actually be 0.09999999999997 or 0.1000000000002. This can lead to the unexpected results I mentioned earlier. If you must increment a value by a fractional portion of a whole number, and you absolutely cannot have the loop run “too few” or “too many” times, use a whole number variable type for the loop counter, and calculate the fractional portion as a percentage of the loop counter within the loop.

Note also that the Variable name in the Next N statement is optional. However, it makes the loop easier to understand, especially in the case of nested loops, if the variable name is included.

The For-Next loop also offers a way of exiting the loop early. You would place a test within the loop, and use the key phrase "Exit For." For instance, suppose that the loop should immediately quit processing and continue on with the rest of the application if a tilde (~) is found in the test string. You would simply add the line:
Code:
If Mid$(strTest,N,"1") = "~" Then Exit For
just after the For N = 1 to Len(strTest) line in the example. Keep in mind that this is an implied GoTo in your code, and a structured programming code purist may take issue with its use. I don't, as long as it is used sparingly.

Also, remember that you may specify the direction that a for-loop iterates, and the size of the step that it takes. For example, in order to have a loop iterate from 10 to 0, only processing the even numbers, you would code the loop as
Code:
For N = 10 to 0 Step -2

For-Each Loop

Although similarly named, The For-Each loop is specifically designed for looping through collections of objects. For instance, suppose that I wish to print the contents of 30 textboxes on my printer, with the position of each textbox being accurately reflected in the printed position of the text on the paper. I could code the printing as:
Code:
Private Sub PrintForm () Printer.xPos = TextForm1.Left Printer.yPos = TextForm1.Top Printer.Print TextForm1.text Printer.xPos = TextForm2.Left Printer.yPos = TextForm2.Top Printer.Print TextForm2.Text ' ... through TextForm30 End Sub
Now, this will get tedious in a hurry. Even with the ability to cut and paste! A more efficient, "Civilized" approach would be for me to create a control array of textboxes (Named TextForm(0) through TextForm(29). Then, I can set up my print routine as follows:
Code:
Private Sub PrintForm () Dim theText as Textbox Set theText = new TextBox For Each theText in Me.TextForm Printer.xPos = theText.Left Printer.yPos = theText.Top Printer.Print theText.text Next End Sub
For each iteration of the For Each loop, as I work with theText, it is really the underlying control that is being referenced by theText. Note that this approach will print the controls in the order that they were created on the form. Since this means that I won't necessarily know the order that the controls will be printed, I can use the Index property or the Tag property of the control to good effect.

Do Loop

The Do loop is used where you don't know precisely when a loop should end when you are writing the code. The Do loop is often used when reading files, where you don't know how many lines of text are in the file, or in processing a database recordset, where you aren't sure how many records were returned from the database. These types of loops will run until a condition becomes True or False. There are two variations of the Do loop - the Do While and the Do Until. Examples of both are shown below:
Code:
Open "C:\Test.Txt" for Input as #1 Do While Not EOF(1) Line Input #1, strLine Me.FileText.Text = Me.FileText.Text & strLine Loop Close #1 Open "C:\Test.Txt" for Input as #1 Do Until EOF(1) Line Input #1, strLine Me.FileText.Text = Me.FileText.Text & strLine Loop Close #1
A second variation of the Do While loop places the condition check (While, or Until) at the end of the loop. This will force the loop to run at least once, since the condition check is at the end of the loop. If the condition is placed at the beginning of the loop, it might not run at all.
Code:
Do Line Input #1, strLine Me.FileText.Text = Me.FileText.Text & strLine Loop While Instr(theLine,Chr(27)) = 0

While-Wend Loop

There is actually a fourth loop structure in VB: the While-Wend loop. This loop structure is considered obsolete however, and is only included for backwards compatibility with earlier versions of Basic. Its use is not recommended. If it must be used, the syntax is:
Code:
While Condition Statements Wend

If Then Goto Loop

It is possible to create your own loop structure in VB, using an If Then condition check, and the Goto statement to loop back (or ahead) to a label in the code. This is NOT a good choice, however. First, there is really no need to create your own looping structure, when VB offers looping structures that work well for all conceivable loops. Secondly, the use of the GoTo statement is frowned upon, and should rarely be used. In fact, it should rarely ever need to be used (except in one particular instance, which will be discussed later.)

Why should you avoid the use of GoTo's in your code? It's largely a matter of maintainability - it can be very difficult to follow code that uses GoTo's, as the code execution can jump around from point to point to point. In fact, the term Spaghetti code came into existence as referring to code that makes extensive use of the GoTo statement. The widespread use of the GoTo statement in a program is considered to be a dead giveaway of an unskilled VB programmer. alp0001 recently forwarded a link to an essay by Edsger Dijkstra, discussing the problems associated with GoTo way back in 1968!

Now, the single instance that I referred to earlier, where it can be desirable in VB to actually use a GoTo, is when you want to write your own error handler. In this case, place the error handler at the end of your Sub or Function, with a label to identify the error handler, and add a statement at the front of the sub that states:
Code:
On Error Goto ErrorHandlerLabel

This line will direct the application to jump to the error handler in the event of an error. Then, within the error handler, you can decide how to handle the error. If you can recover, use a resume statement to cause your app to continue from where the error occurred. Otherwise, you may have to exit the sub, or under some circumstances, you may even choose to end the application outright.

In conclusion then, Visual Basic offers three main looping structures, each with several variations. The For-Next loop is best suited for uses when you know, or will know at program execution, the number of iterations needed. The Do-Loop, on the other hand, is better suited for those instances where you won’t know how many times the loop needs to run. The For-Each loop structure is designed to interface closely with collections of objects. And, when you program a loop, be sure not to use floating point loop counters when you test for equality.
__________________
Lou
"I have my standards. They may be low, but I have them!" ~ Bette Middler
"It's a book about a Spanish guy called Manual. You should read it." ~ Dilbert
"To understand recursion, you must first understand recursion." ~ unknown

Last edited by loquin; 03-30-2006 at 02:17 PM.
Reply With Quote
  #8  
Old 03-04-2003, 11:21 AM
loquin's Avatar
loquin loquin is offline
Google Hound

Retired Moderator
* Guru *
 
Join Date: Nov 2001
Location: Arizona, USA
Posts: 12,402
Default You can call me arRay...

In VB, Array is not a beam of sunshine. Arrays are just a way of grouping identical types of variables under a common name. Suppose you want to hold the top 10 high scores for a game. You could define an array as
Code:
Dim intHiScoreArray(9) as Integer
"Wait a minute!," you're saying. "Didn't he just say 10 high scores?" Well, yes, but by default, arrays start numbering at 0, not 1. So, 0 through 9 is actually 10 elements. (To further confuse things, VB will allow you to change the default low array element number to one instead of zero – just add the statement “Option Base 1” at the beginning of the form or module. However, for this installment, I’m assuming Option Base 0)

To save a value into this array, you just need to access the variable name, as with any other variable. However, since you also need to specify which of the 10 elements you need, the array element number is also required. Let's say you need to update the 7th array element. You would do so like this:
Code:
intHiScoreArray(6) = 17300

To list all the values in the array, you could refer to every array element individually, but this sort of code is pretty inefficient, and gets very tedious. I would suggest using a loop and just iterate through all the array elements. (see the installment above for a discussion of looping)
Code:
Dim N as Integer For N = 0 to 9 Me.Print intHiScoreArray(N) next N

That’s all there is to it! Arrays are just a piece of cake…

When defining arrays, you may specifically define the upper and lower bound for the array. Lets say you want to create an array of integers with elements from 100 to 200, inclusive.
Code:
Dim intMyArray (100 to 200) as Integer

Now, lets assume that we’re working on the best crossword puzzle program since Henry Ford introduced the Edsel! You are going to display the crossword in full black and white. So, how are you going to keep track of what letters go into which squares? Well, since this article is all about arrays, you’ve probably guessed that we’ll store those letters in an array. Very astute of you! But, since crossword puzzles have letters running both horizontally AND vertically, how do we handle that? Lets define a two-dimensional array. For the moment, we’ll say that the crossword can be no larger than 15 squares wide by 15 squares high, so, we define our array as
Code:
Dim strXWordArray (14,14) As String
That’s it! You’ve just created an array to hold 225 strings (15*15.) To write the words VISUALBASIC (down) into column 8, starting at row 4:
Code:
Dim strWord as String Dim N as Integer strWord = "VISUALBASIC" For N = 3 to 3 + Len(strWord) StrXWordArray (7,N) = Mid$(strWord, N+1, 1) Next N
There’s no real hard and fast rules, in an array definition, as to which array element comes first – just pick one, but (most importantly) stick with the convention that you pick. Since most two dimensional convention is to specify X (or horizontal displacement) first, then Y, you might wish to stay with this.

Can you carry array dimensioning further? Sure. Just define the number of dimensions that your array must hold. Suppose you have an array of elevations for a river delta that changes over time. (Which they do) This array is an xyz plot, with the z (elevation above sea level) quantity being a double. Furthermore, the area you’re storing is a 10 kilometer by 10 kilometer grid, your measurements are 100M apart, and you need to store the data from the last 10 years, in addition to the base reading. Since we have edges (boundries) to include, the array would defined as:
Code:
Dim dblElevations (100, 100, 10) As Double
For our example, we could define the first dimension as the East-West displacement, with 0 being the western boundary of our “map”, the second dimension being the North-South displacement, with 0 being the southern boundary, leaving the third dimension as time, with 0 being the base elevation measurement from at least ten years ago. This leaves us with the vertical displacement, or elevation being the actual data stored in the array. To see the elevation of a point 3.7 Km from the western boundary, 4.2 Km north of the southern boundary, 7 years after we started keeping the data, you would refer to dblElevations(37,42,7)

OK. This is as far as I’ll go for now with multi-dimensional array definition. Now, lets take a look at Dynamic arrays. First, a dynamic array is an array whose dimensions are not defined at compile time, but is instead defined at run time. This means that you don’t have to worry about reserving enough space to hold every element that you might need to store. Instead, you can define an “empty” array of whatever type you need, then change the size to fit your needs when the app runs. Wow! To do this, simply define an array, as we did earlier, but leave the quantity blank:
Code:
Dim strLineArray () as String ' ' Here we define the size ReDim strLineArray(200)
“Now I know what to do! Never assign a fixed array – always make it dynamic! My troubles are solved!” Well, maybe not. As with most decisions, there are trade-offs to consider. Having a fixed array can be expensive in terms of memory requirements – you have to define the array size up front, and the memory requirements are fixed for the life of the array. However, Dynamic arrays, while they use only the amount of memory that you specify at run-time, are “expensive” to create in terms of CPU processing time, and are especially processor intensive if you wish to retain the data that is already in an array (more on this later.) As with many other programming decisions, your decision is really one of a trade-off between size and speed. If you have a well-defined quantity of items to store, or the speed of the application is critical, use a fixed array. If you won’t know how many items you need to store, then make the array dynamic.

If you decide to use dynamic arrays, there are some techniques that may help speed up your processing. Suppose, for instance, that you’re reading lines from a text file, and you know that there will usually be at least 100 lines in the file, but the upper limit could be almost anything. When your app starts, ReDim the array to 100 elements. This means the first 100 reads will take place fairly quickly. But, we’ll need to keep track of how full the array is, so we must increment a counter whenever we read a line from the file.

If we’ve filled up the array, THEN we re-size it. But, not just one new element at a time. Let’s add 100 new elements every time. Keeping space down is important. However, a hundred empty strings don’t take that much more space in memory, but reDimming a 100 extra elements takes little longer than reDimming one extra element. Our code for reading the file would look something like this:
Code:
Const intChunkSize as Integer = 100 Dim strLines () as string ' The array for our text lines Dim lngFileCount as Long ' The file counter Redim strLines (intChunkSize) ' Set the initial array size lngFileCount = 0 Open "C:\MyTextFile.Txt" for Input as #1 Do While Not EOF(1) If lngFileCount = Ubound(strLines) then ' See if we have enough space ReDim Preserve strLines (lngFileCount + intChunkSize) ' Increase array size End If Line Input #1, strLines(lngFileCount) ' Read the line from the file LngFileCount = lngFileCount + 1 ' and increment the line counter Loop Close #1
That’s it. On average, you’ll have 50 spare array elements when you’re through reading the file. Note a couple of things in the above example: First, the Ubound function is used to determine the upper bound of the array. Ubound has a complementary function called Lbound, which returns the lower bound of an array. Also, the Preserve keyword is used inside the loop when redimming. This tells VB to keep all the data that is currently in the array. Also, I would like to bring up one more item regarding dynamic arrays. If you have a multi-dimensional dynamic array, you may only redim the last element of the array if you wish to preserve the data. In the following example, for instance, the last statement is illegal; you will get an array out of bounds error:
Code:
Dim myArray() As Integer ReDim myArray(5, 25) ' Ok ReDim myArray(6, 30) ' Ok ReDim Preserve myArray(7, 35) ' NOT Ok
If you really need to create a totally dynamic array, I won’t get into the mechanics of how to do so here – this is, after all a basic tutorial, but, you could create a dynamic array of dynamic arrays… Hmmm.

There are several functions that work closely with arrays. The first is called Array. This is somewhat confusing, but you must admit that it is easy to remember! You pass an argument list to Array; it returns a variant, holding an array with your arguments in the array elements.
Code:
Dim A as variant A = Array("Tom", "Dick", "Harry")
creates a three element variant array & places it into variant A.

Another commonly used function is the Split function. Split is used to break apart a string on delimiting characters, and place the discrete strings into a dynamic array. Consider the following:
Code:
Dim strWords() as string Dim strSentence as string StrSentence = "Jack and Jill went up the hill" StrWords = Split(strSentence, " ")
In this example, strWords(0) would contain "Jack", strWords(1) would contain "and", strWords(2) would contain "Jill", and so on. The delimiter could be any character, or any string of characters. The comma is a common delimiter, used in comma separated variable data files.

Well, that’s about it for a beginning discussion of Arrays. One of my Dad’s favorite sayings was "Don’t put all your eggs in one basket." But, with VB, it can be a LOT easier if you do put all your eggs… er, data, into one array.
__________________
Lou
"I have my standards. They may be low, but I have them!" ~ Bette Middler
"It's a book about a Spanish guy called Manual. You should read it." ~ Dilbert
"To understand recursion, you must first understand recursion." ~ unknown

Last edited by Squirm; 03-29-2003 at 12:17 PM.
Reply With Quote
  #9  
Old 01-08-2004, 04:54 PM
loquin's Avatar
loquin loquin is offline
Google Hound

Retired Moderator
* Guru *
 
Join Date: Nov 2001
Location: Arizona, USA
Posts: 12,402
Default

I once worked with an older gentlemen named Walt. Walt was a great guy, but I believe that in every meeting he ever attended in his life, and at least a half-dozen times a day, he would use the expression that you "Need to get your ducks in a row."

Those $%)!$ Ducks! The Publicity they got! I used to get so irritated with that phrase. But, the more I think about it, the more appropriate the phrase seems to the field of programming. Although you can apply the concept of getting everything ready to go before you begin the next task in many areas in our profession, I really think those ducks may have the best application during the design process.

One of the areas where most of us can do a better job is in planning and preparation before actually writing any code at all. It's all too easy to just jump in, feet first, and begin coding. But, there's a real danger, that, if you do, you can lose track of the direction that your application is headed, and you can end up missing critical areas. Then, the re-writes begin, and the "I've spent so much time coding this area that I don't want to re-write it, so I can just tweak this a bit to compensate..." can begin.

The answer of course, according to those darn ducks, is to work on the project as a whole, at a high (or abstract) level, before coding anything at all, to ensure all requirements are met. Many programmers, myself included, use what is known as a stepwise approach here. First, define, at a very high level, just what the application or system is to accomplish. Then, at the next step, break out, or refine this concept to a series of processes or procedures. Complete this step, then break the processes or steps down further.

Each of the descriptions we talked about above can be thought of as pseudo-code. The first iterations through the process include pseudo-code that is very abstract, but as you refine the levels, the pseudo-code steps closer and closer to real VB code. Eventually, you translate the pseudo code to actual code, and the application is complete!

Well, Isn't VB/Basic about as close to pseudo-code as you can get? It seems 'Basic'-like code is often given whenever an algorithm is described with pseudo-code in books and such. Not Really. It's true that the Basic language was developed with the intention of following an English-language syntax as much as possible, which makes it somewhat closer than others (Pascal also adheres to a similar syntax, although more rigidly defined structure) but you have to remember, pseudo code can have different levels of abstraction which can make it very close to true code, or fairly far removed from code. Generally, I usually use the stepwise approach using pseudo code, in the design cycle. In this approach, you begin at a very abstract, "high" level, and gradually focus in, or step closer to code.

Under this methodology,
Code:
Process the File
becomes

Code:
Open the File
Scan the file line at a time, looking for key characters
Process the fields after the key characters
Close the file.
which in turn is expanded to code:
Code:
' Open the File iFileNo = FreeFile Open sFileName for Input as #iFileNo ' Scan the file line at a time, Do While Not EOF(iFileNo) sLine = Line Input #iFileNo ' looking for key characters If Instr (sLine,sKeyVal) > 0 then ' Process the fields after the key characters sTemp = Mid$(sLine, Instr (sLine,sKeyVal) + 1) sFields = Split (sTemp, ",") ' Build the SQL Insert command, execute ' ... End If Loop ' Close the file. Close #iFileNo
The level at which you, as a programmer, makes the step from pseudo code to code varies, depending upon your skill and experience level. As you get more experienced, the steps become larger and larger.

Both the above blocks are psuedo code (at different levels of abstraction,) which can eventually become the comments for the program, as code is added to it to support the functionality needed for the pseudo code.

The main advantage of pseudo coding first (aside from the self-documenting feature, that is) is that by forcing yourself to work more abstractly initially, you can work out the program logic flow first, before throwing code at the problem & getting bogged down in detail. The process results in a program that is less expensive to write.

Less expensive to Write??? How can THAT be, when you spend more time working you way through those steps? It's less expensive to write when using a step-wise design approach (or other structured methods) because you've spent more time, up-front, in ensuring that the application/system design is appropriate to your needs. You will spend less time in re-writes of code, and less time troubleshooting programming logic errors. An error fixed in the design stage is MUCH less expensive to fix than one discovered later in the project. Period. Your app will cost less to write and troubleshoot, and certainly, over the long run, have a lower total cost of ownership. In addition, because the app is laid out more logically, it can often be MUCH easier to troubleshoot, and will often be more reliable. Again, this is because more thought is given to the app during the design process. Finally, a well structured design will be easier and less expensive to maintain.

There are many different methodoligies used in the software design field, each with their own supporters. Some folks swear by flowcharting. (I swear AT them, myself ) Each of us need to find an approach that allows us to line up those ducks, though. Otherwise, on your next project, you may find youself chasing a wild goose.
__________________
Lou
"I have my standards. They may be low, but I have them!" ~ Bette Middler
"It's a book about a Spanish guy called Manual. You should read it." ~ Dilbert
"To understand recursion, you must first understand recursion." ~ unknown

Last edited by loquin; 10-21-2004 at 05:32 PM.
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

Advertisement:





Free Publications
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET.
subscribe
Programmers Heaven C# School Book -Free 338 Page eBook
The Programmers Heaven C# School book covers the .NET framework and the C# language.
subscribe
Build Your Own ASP.NET 3.5 Web Site Using C# & VB, 3rd Edition - Free 219 Page Preview!
This comprehensive step-by-step guide will help get your database-driven ASP.NET web site up and running in no time..
subscribe
 
 
-->