reduce public variables

R

RB Smissaert

When you have a large application with lots of modules and forms and a large
number of public variables what would be the best way to organize and reduce
these public variables?
Making all these variables private or local is not an option as it would
mean an enormous duplication of code.
The 2 options I can see are making classes or UDT's and maybe UDT's are the
simplest option.
So with a UDT I would get a public type with a number of elements that are
the old public variables.
Then there would be a public variable declared as this public type.
Would this make sense or are there any better options?

RBS
 
B

Bob Phillips

Bart,

I must ask, why bother? Whatever you do you are left with a number of
variable/properties that would be used irrespective. I personally wouldn't
create a class just for public variables, as I like classes to be object
based, and this class wouldn't be, and I fail to see any advantage of UDTs
or Enums.

Old maxim, if it ain't broke, why fix it?

--

HTH

Bob Phillips

(replace xxxx in the email address with gmail if mailing direct)
 
R

RB Smissaert

Bob,

2 reasons:
One, an irrational one. Loads of public variables seems to be frowned upon
generally.
Two, you can see better what is going on.
For example, I have an .ini file that generates lots of public variables.
If I made a UDT for that and one public variable then with intellisense I
could see directly
all my public values related to this .ini.

RBS
 
K

keepITcool

Alternatively you can:

Use 1 long with 'bit flags' to replace a series of booleans.
(you'll need to add several constants (or enums if you code for VBA6),
but I find it very convenient for managing data from and to userforms
with many options.

Use arrays for similar variables of same type. Use constants to
identify the position in the array. e.g. iso
rngMain,rngDest,rngSource,rngTemp you'd use
arng(MAIN),arng(DEST),arng(SOURCE),arng(TEMP)


Arguably the above may look like cosmetics, but I find it produces more
readable and manageable code (reset 20 range variables with erase arng)
Further it's fairly easy to implement in an existing situations
with (CAREFULL) search & replace. (use MZtools!)
 
R

RB Smissaert

Interesting the idea of an array with constants for the array index.
As you say, it has the benefit above a UDT that you can loop through it.
You can't do that with a UDT or can you?

Didn't get this one:
Use 1 long with 'bit flags' to replace a series of booleans.
Could you give a simple example?

RBS
 
K

keepITcool

Consider a userform with a few related checkboxes for string
manipulation: to transfer/store the settings you could use 1 long (eg.
lngStrConv iso 5 booleans: blnEnabled, blnUpperCase, blnTrimLeading,
blnTrimTrailing, blnRemComments.

Somewhere you define the constants for the flags
(note the values use sequential and exclusive bits)
Const lscENABLED = &H1&
Const lscUPPER = &H2&
Const lscTRIML = &H4&
Const lscTRIMT = &H8&
Const lscREMCMT = &H10&

'setting the long would look like:
if chkEnabled then lngStrCont = lscENABLED
if chkUppercase then lngStrConv = lngStrConv OR lscUPPER
if chkTrimLeading then lngStrConv = lngStrConv OR lscTRIML
if chkTrimTrailing then lngStrConv = lngStrConv OR lscTRIMT
if chkRemComments then lngStrConv = lngStrConv OR lscREMCMT


'Using the individual flags somewhere else could look like:
If lngStrConv and lscENABLED then
If lngStrConv And lscUPPER then
s = UCase$(s)
end if
if lgnStrConv And lscTRIML then
s = LTrim(s)
end if
end if

You'll have to get comfortable with working with bits/flags.
but once familiar it's not difficult. However be carefull with NOT.
often you must use NOT CBool(lngMask AND flag)

e.g
?13 AND 4 = 4
?Not 4 = -5
?cbool(-5) = TRUE
but
?not cbool(13 and 4) = FALSE

HTH
 
R

RB Smissaert

OK, I understand.
I think I will take the .ini file related variables and change them to
elements
of a UDT and see how that is suiting me.
I don't need the option to loop through a load of these variables, so I
think
the UDT is better here than the array with constants for the array index as
with
the UDT I will have the intellisense.
Maybe in the end I might come to the same conclusion as Bob Phillips, if it
ain't broke, don't fix.

RBS
 
B

Bob Phillips

Bart,

Don't forget with any variables, you get a form of intellisense if you type
the first few letters then hit Ctrl-Spacebar.

--

HTH

Bob Phillips

(replace xxxx in the email address with gmail if mailing direct)
 
R

RB Smissaert

Bob,

Didn't know that one, thanks for the tip.
Not sure if it helped that much in this particular situation as it means to
take advantage of that I would have
to rename for example all my .ini file related variables. For example start
with bINI, strINI etc.
I think the UDT is the best option.

What is actually so bad about public variables, apart from the fact that it
can make the code more difficult to understand?

RBS
 
B

Bob Phillips

Don't know Bart, I see no problem with them. They don't even make the code
more difficult to understand IMO, if you use proper commenting and sensible

--

HTH

Bob Phillips

(replace xxxx in the email address with gmail if mailing direct)
 
B

Bob Phillips

Don't know Bart, I see no problem with them. They don't even make the code
more difficult to understand IMO, if you use proper commenting and sensible
names they are just as 'easy' to understand as classes, UDTs, or any other
variant.

--

HTH

Bob Phillips

(replace xxxx in the email address with gmail if mailing direct)
 
R

RB Smissaert

Nice to know that. How about though say 1000 public variables?
I can see one potential drawback now with using a UDT and that is if it is
used
in a long loop. Haven't tested but I suppose repeatedly doing UDT.Element
could
have some performance penalty. So that would mean I would need to make a
local
variable and use that in the loop.

RBS
 
R

RB Smissaert

Have tested UDT element versus variable and luckily there doesn't seem any
performance difference at all:

Option Explicit

Private Type UDT_Test
str1 As String
str2 As String
str3 As String
str4 As String
str5 As String
str6 As String
str7 As String
str8 As String
str9 As String
str10 As String
str11 As String
str12 As String
str13 As String
str14 As String
str15 As String
str16 As String
str17 As String
str18 As String
str19 As String
str20 As String
str21 As String
str22 As String
str23 As String
str24 As String
str25 As String
str26 As String
str27 As String
str28 As String
str30 As String
End Type

Private Declare Function timeGetTime Lib "winmm.dll" () As Long
Private lStartTime As Long
Private lEndTime As Long

Sub StartSW()
lStartTime = timeGetTime()
End Sub

Sub StopSW(Optional ByRef strMessage As Variant = "")
lEndTime = timeGetTime()
MsgBox "Done in " & lEndTime - lStartTime & " msecs", , strMessage
End Sub

Sub UDTTester()

Dim i As Long
Dim uTest As UDT_Test
Dim strTest As String
Dim strVar As String

uTest.str25 = "testing"
strVar = "testing"

StartSW

For i = 1 To 10000000
'strTest = strVar
strTest = uTest.str25
Next

StopSW

End Sub


RBS
 
G

Guest

I am not to sure if it helps but I have a class module for reading and
writing ini files. That way you won't need to store the settings, you can
just read them on the fly. I will send you a copy... Here is the code
though...

Class*****************
Option Explicit
Private c_strSection As String
Private c_strKey As String
Private c_strININame As String

Public Property Let Section(strSection As String)
c_strSection = strSection
End Property

Public Property Let Key(strKey As String)
c_strKey = strKey
End Property

Public Property Let ININame(strININame As String)
c_strININame = strININame
End Property

Public Function ReadINISettings() As Variant
Dim sDestination As String * 255
Dim lReturnVal As Long

On Error GoTo ErrorHandler

lReturnVal = GetPrivateProfileString(c_strSection, c_strKey, "", _
sDestination, Len(sDestination), c_strININame)

'lReturnVal will always equal the length of the returned string not
including vbNullChar 's at the end!!!
If lReturnVal <> 0 Then
sDestination = Left(sDestination, InStr(sDestination, Chr(0)) - 1)
'chr(0)=vbNullChar
ReadINISettings = Trim(sDestination)
Else
Err.Raise vbObjectError + 513 + 1001,
"clsINISettings.ReadINISettings", _
"Initialization File Error!"
End If

Exit Function
ErrorHandler:
MsgBox "Error Number: " & Err.Number & vbCrLf & _
"Error Description: " & Err.Description _
, vbCritical, "Initialization File Error"
End Function

Public Sub WriteINISettings(ByRef strWriteValue As String)
Dim lReturnVal As Long

On Error GoTo ErrorHandler

lReturnVal = WritePrivateProfileString(c_strSection, c_strKey,
strWriteValue, _
c_strININame)
If lReturnVal = 0 Then Err.Raise vbObjectError + 513 + 1001, _
"clsINISettings.WriteINISettings", "Initialization File Error!"
Exit Sub

ErrorHandler:
MsgBox "Error Number: " & Err.Number & vbCrLf & _
"Error Description: " & Err.Description _
, vbCritical, "Initialization File Error"
End Sub

Module*********************
Option Explicit

'API Function Declarations
Public Declare Function GetPrivateProfileString Lib "kernel32" Alias
"GetPrivateProfileStringA" ( _
ByVal lpApplicationName As String, _
ByVal lpKeyName As Any, _
ByVal lpDefault As String, _
ByVal lpReturnedString As String, _
ByVal nSize As Long, _
ByVal lpFileName As String) As Long

Declare Function WritePrivateProfileString Lib "kernel32.dll" Alias
"WritePrivateProfileStringA" ( _
ByVal lpApplicationName As String, _
ByVal lpKeyName As Any, _
ByVal lpString As Any, _
ByVal lpFileName As String) As Long

'Global Variables
Public INI_SETTINGS As clsINISettings

Public Sub Auto_Open()
Set INI_SETTINGS = New clsINISettings

INI_SETTINGS.ININame = ThisWorkbook.Path & "\" & "Settings.ini" 'pass
INI file location and name
End Sub

Public Sub Auto_Close()
Set INI_SETTINGS = Nothing
End Sub

User Form***********************
Private Sub UserForm_Initialize()

On Error GoTo ErrorHandler

With INI_SETTINGS
.Section = "StartUp"
.Key = "UID"
txtUID.Text = .ReadINISettings
.Key = "Server"
txtServerName.Text = .ReadINISettings
.Key = "DBName"
txtDBName.Text = .ReadINISettings
.Key = "Driver"
txtDriver.Text = .ReadINISettings
.Section = "Test"
.Key = "Test"
txtTest = .ReadINISettings
End With
Exit Sub

ErrorHandler:
MsgBox "Error Number: " & Err.Number & vbCrLf & _
"Error Description: " & Err.Description, _
vbCritical, "frmMain.FormLoad"
Err.Clear
End Sub

Private Sub cmdTestThat_Click()
With INI_SETTINGS
.Section = "Test"
.Key = "Test"
.WriteINISettings ("That")
End With
frmMain.Show
End Sub

Private Sub cmdTestThis_Click()
With INI_SETTINGS
.Section = "Test"
.Key = "Test"
.WriteINISettings ("This")
End With
frmMain.Show
End Sub
 
R

RB Smissaert

Jim,

Thanks, but I know how to read .ini values. I just do it with a simple
function,
very similar to your code:

Declare Function GetPrivateProfileString Lib "kernel32" Alias _
"GetPrivateProfileStringA" _
(ByVal lpApplicationName As String,
_
ByVal lpKeyName As String, _
ByVal lpDefault As String, _
ByVal lpReturnedString As String,
_
ByVal nSize As Long, _
ByVal lpFileName _
As String) As Long

Function ReadINIValue(ByVal strINIPath As String, _
ByVal strHeader As String, _
ByVal strKey As String) As String

'will return <no value> if the header or the key is not there
'will return <no file> if the .ini file is not there
'------------------------------------------------------------
Dim buf As String * 256
Dim Length As Long

If bFileExistsVBA(strINIPath) = False Then
ReadINIValue = "<no file>"
Exit Function
End If

Length = GetPrivateProfileString(strHeader, _
strKey, _
"<no value>", _
buf, _
Len(buf), _
strINIPath)

ReadINIValue = Left$(buf, Length)

End Function

Public Function bFileExists(ByVal sFile As String) As Boolean

Dim lAttr As Long

On Error Resume Next
lAttr = GetAttr(sFile)
bFileExists = (Err.Number = 0) And ((lAttr And vbDirectory) = 0)
On Error GoTo 0

End Function


I don't want to read the .ini values repeatedly, particularly in loops, so I
will
have to read the values at startup and store them in some sort of variables.
I think a UDT fits the bill nicely and that is how I am doing it now.

RBS
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top