Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Advanced programming style discussion 2

Status
Not open for further replies.

ESquared

Programmer
Dec 23, 2003
6,129
US
Hi!

My name is Erik. I have been programming for 22 years. Admittedly, I was 9 years old when I started and I don't have all that much "professional programming experience" under my belt, but I'm getting there.

Lately I've been repeatedly running into certain similar problems across all the programs I am writing. My hope is that I can start a discussion with some programmers who are more experienced than I, and get a few tips. I don't know where else to go, there is no one here at work I can ask and I don't know anyone who has the experience I am trying to tap in to.

I am not sure how much to put in one question. My hope is that someone can see what I am driving at and help me ask the questions I don't even know how to ask!

With that somewhat incoherent preamble, I'll begin.


How important is it to avoid global variables? I have worked hard not to use them, one because I have read again and again since I started that they are bad, and two because my programming experience has proven this out. Globals can work when you have two or three variables, but when you have 10 or 20 or 100, it's time to do something different. Yet, sometimes in my quest to avoid globals I run into difficulties finding an elegant solution.

For example, VB does not allow a function to return an array. That is, it can return a variant which contains an array, but it cannot return an array of variants (or longs, or strings, or anything else).

Well, first of all I have been avoiding variants, too, because they seem... well, wrong or sloppy somehow. So to avoid using a variant which contains an array, and avoid using a global variable, I set up the function to receive the array as a parameter, ByRef of course.

Then I run into another problem. The calling function doesn't know how big the array needs to be. For example, Let's say I write a class module which connects to a dictionary of words. The class module does all the work of managing the dictionary: provides methods to load dictionaries from files, add words, delete words, return all words which start with a string or contain a string or are anagrams of a string. It even builds its own 2-level large index to optimize speed. You get the idea.

Now, let's say it makes sense for one function in clsDictionary to "return" an array instead of a collection or a recordset or any other method of containing many values. If I declare an array in my calling code, I don't know how big it needs to be, so I Dim it as empty() and figure I can resize it as necessary.

Wrong. You can't ReDim an array in anything but the scope in which it was declared. You don't get a runtime error, but the code simply doesn't work, and VB help confirms that you can't resize arrays which are passed as parameters.

What is wrong with my thinking? Should I just use variants? Should I use globals? Should I mess around with RtlMoveMemory and VarPtr? Should I use collections or recordsets or classes?

If you do chip in to help me out, please understand that I am looking for high level answers. That is, you could give me an idea on how to do what I'm asking, but what I really want is a why. I guess I am asking for strategies, not tactics.

I think this is enough for one question. I was going to give quick bullets of my other 10 burning programming style problems but every time I tried it came out too long, so I'll leave those for another message.

-E

 
Not terribly relevant in this forum and on today's big machines, but the other traditional problem with global variables is that in most languages they take up memory for ever, even when you're not using them. (The same applies in C to static things you want to stay unchanged from one function call to the next, even though they're only in scope inside the function). Worse, in the good old days of dos, many languages only provided one 16-bit segment for all global data, and it wasn't too hard if you defined a few hefty arrays to run out of global space.

And of course globals are utterly hopeless if there's any element of recursion in your code.

But creating bugs is the real problem. And you would not believe it, if you call your variable "SpecialVariableMadeOn12thDecemberToCountChickens" you can be utterly certain next 12th of December someone else will be counting chickens and have the same idea. It's uncanny.
 
lionelhill

Yes i see your point for ever living in memory.I espacially like the december var thing,funny.

Thank you all that have inputed their views on global.We always made sure we din't over used globals, but i had never really had a clear opinion on why, although i had my own conception about the scope.But in a event driven program, some data need to be caried over the long inactive time.Re-aquiring data when you don't know if the downtime will be 1 sec or 10 min can slow your process greatly,no?





 
What do you mean by re-acquiring data? You mean, if you don't store something in a global, you have to go get it again?
 
Well yes, it is what i meant.


Like on a 24-7 app that could have command inputed every second for 3 minutes then left alone for two hours and such.

That kind of stuff
 
You can retain things in memory without using globals. Personally I like structures and objects to contain large amounts of information. One persistent object to keep your values "active" and as many user-defined types as you like inside of it.
 
So basicly,Use a global object that contains local values and types to him and even private.

Well, yes you do have a point!But by persistent you really mean global to program?

You know what,i like this idea!

Thank you,so simple and yet...
 
By persistent I mean either one global, or better, passed around as function parameters.

[tt]Sub Main()
Dim lngRetVal As Long
Dim clsStorage As New MyStorageClass

With clsStorage
.ImportantValue1 = "frog"
.ImportantValue2 = "princess"
.MyTypeVar.Bananas = 7
End With

GoDoSomeImportantStuff clsStorage

lngRetVal = NowDoSomeMoreStuff(clsStorage)
Select Case lngRetVal
Case meMyEnumBadThingsHappened
' Scream and eat a banana
Case meMyEnumGoodThingsHappened
If clsStorage.Result = myKissSuccessful Then
' Yodel for joy
End If
Case meMyEnumTheUniverseExploded
' Design a new universe
Case Else
End Select
End Sub[/tt]

I really need to learn exactly how to use the instancing parameter for DLLs and EXEs I create. I read about MultiUse and SingleUse and GlobalMultiUse and still don't have it completely down. I suspect, though, that this could help solve part of the avoiding-globals problem if you can go instantiate a class and get a reference to the same object that another program already has (on the same or another computer).
 
I can't read that article. Even after the free registration, I don't meet the requirements to read it. :(
 
Well, they supposedly have some content that is available without paying. Since the URL was provided I hoped this was one of those items. It's not. :(
 
ACM freebies:

Content, yes. Digital Library, no.

(If the Digital Library were free, how would they get members to pay for it?)
 
I tried running the following piece of code:

Private Sub Command1_Click()
Dim rtn() As String
Dim iX As Long

rtn = ReturnArray(10)
For iX = 0 To UBound(rtn)
Debug.Print rtn(iX)
Next
rtn = ReturnArray(7)
For iX = 0 To UBound(rtn)
Debug.Print rtn(iX)
Next
End Sub

Private Function ReturnArray(ByVal FillTo As Long) As String()
Dim iX As Long
Dim arr() As String

ReDim arr(FillTo)
For iX = 0 To FillTo
arr(iX) = "Added " & CStr(iX)
Next
ReturnArray = arr
End Function

but I got a syntax error. It didn't like the as string() part in the Private Function line. I tried it in VB 5. Does that mean that VB 5 can't have functions return arrays?

 
I believe that is correct, Eurt.

Sucks, don't it? :(
 
My view on the use of global variables, is that I will only use them for a data item which does not change once set within the program.

For example, if I want the title bar of all message boxes displayed by my program to include a Company Name, I think it is straightforward to use:
Code:
Global stCompanyName as string
Then, in an initialisation routine,
Code:
stCompanyName = "Bloggs Widgets plc"
Once set, this variable obviously never changes while the program is running.

I suggest if you limit use of global variables to this type of 'static data' then you do not have a problem.

I agree completely that using global variables to hold dynamic data is dangerous!


Bob Stubbs
 
Er...Bob that would be an example of a good time to use a Constant...
 
Personnaly I prefer to use a global class objects

This class can contain all global variables that you want to use. By using the get and let properties to control the flow of data, you can format and validate all data in both directions (writing and reading)

It's overkill for simple programs, but is very good for complex apps

The idea is covered in chapter 5 of the "Advanced Microsoft Visual Basic 5" book on the MSDN disks.

SteveO
 
Well you can't return array of string per say, but you can return an array of variant like this

Code:
varresult = findrecord(strempfile, varparamrech, 2, intfield_number, 2)

If (varresult(1) <> &quot;Not_Found&quot;) Then
    Consumption.TXTOperator(Index).Text = varparamrech(2)& &quot;- &quot; & varresult(2) & &quot;, &quot; & varresult(3)
    Consumption.TGLOp(Index).Enabled = True

*******PROTOTYPE*******************************************

Public Function findrecord(sysfich As String, param As Variant, nbparam As Integer, fields As integer, compare As Integer) As Variant

Dim varkeys As Variant
Dim vartoreturn(3) As Variant
Dim I As Integer
Dim tosearch As CASLINK


Set tosearch = initcas(sysfich)
If (nbparam > 2) Then
    varkeys = Array(param(2), param(1), param(3))
ElseIf (nbparam < 2) Then
    varkeys = Array(param(1))
Else
    varkeys = Array(param(1), param(2))
End If
 
tosearch.CgtRs.Seek varkeys, adSeekFirstEQ

I = 1
If (tosearch.CgtRs.fields(fields(I)) = param(compare)) Then

  While fields(I) <> -1
    vartoreturn(I) = tosearch.CgtRs.fields(fields(I))
    I = I + 1
  Wend
  
   findrecord = vartoreturn
Else
   vartoreturn(1) = &quot;Not_Found&quot;
   findrecord = vartoreturn
End If
Set tosearch = Nothing
End Function

this way, I am able to return array of the fields I need.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top