Visual Basic's Const statement lets you replace magic numbers or text messages with symbolic names. This is like defining read-only variables, and it's a Good Thing because it makes your code
more readable. You should use lots of Const statements. Or should you? Using Const isn't quite like defining variables, because the scope rules don't work the same. Defining constants inside a function is okay, and
defining them at the module level with Private scopes just like a variable too. But just try this in a class module: Public Const eBadUserName As Long = 32767 Now VB doesn't want to play. Why is this
statement illegal? Surely defining read-only variables as properties of a class would be a useful thing? Apparently not; the only place we can define public constants with this syntax is in BAS modules. This is anathema
to modular programing, since even if we want to associate constants with a particular class we have to put them somewhere else. There's a pretty obvious way around this, and one which applies to both VB4 and VB5
(unlike Enums, which I'll talk about later). We can create read-only properties in a class, and these act like constants that are unambiguously associated with that class. For example, here's a constant for an exception
thrown by a class method: Public Property Get eBadUserName() As Long eBadUserName = 32767 End Property This works like 'Public Const eBadUserName...' would work if you could do it, and it
lets us code things like this in exception handlers: Select Case Err.Number Case MyObject.eBadUserName: ... End Select Unfortunately this
isn't quite as good as it first appears, and the reason gives us an insight into why 'Public Const' isn't allowed in classes. The problem is that for this kind of code to work we have to have an INSTANCE of the class
before we can refer to the constant. This means, for example, that the following code doesn't work: Sub MySub
On Error Goto ErrorBlock
Dim MyFirstObj As New CMyFirstClass ' <-- error here Dim MySecondObj As New CMySecondClass ...
Errorblock:
Select Case Err.Number Case MyFirstObj.eThisError ...
Case MySecondObj.eThatError ' Object variable not set ... End Select End Sub
(You might need to think about this a bit before you see why it doesn't work. The problem is that the Select Case statement is going to evaluate the property of MySecondObj even if MySecondObj hasn't been created yet.)
If we're using forms instead of classes, there is fairly elegant (ish) way around this that leads to satisfactory code. It relies on the fact that Visual Basic provides a 'magic form' for each form class we define, and
that, crucially, it gives such forms the same name as the class (see Chapter 1
for more discussion of this). This means we can recode the example above using forms instead of classes, and everything will work fine: Sub MySub
On Error Goto ErrorBlock
Dim MyFirstObj As New CMyFirstForm ' <-- error here Dim MySecondObj As New CMySecondForm ...
Errorblock:
Select Case Err.Number Case CMyFirstForm.eThisError ...
Case CMySecondForm.eThatError ' No problem! ... End Select End Sub Note
the subtle difference between the original example and this one: the constants are qualified with the CLASS name, not the INSTANCE name. This very Java-like syntax works because VB creates instances of CMyFirstForm and
CMySecondForm behind the scenes, and these are used solely to provide the constants. We could almost
do this with an ordinary class too, but first we'd need to create the global instance manually, and second, we couldn't name this instances with the same name as the class. By using forms, we're taking advantage of Visual Basic's peculiar 'magic form' feature, where it contrives to use the same name for a class (form) and an instance of the class. This is even better than
Public Const would be, because we're clearly referring to something that relates to the class and not the instance. The only thing we need to watch out for is that we never actually load
the form (it won't harm, but it doesn't make sense). So should you do this in practice? Maybe. Often it's very useful to use a form instead of a class, particularly if your class is going to have a single form
associated with it. If the class has no visual components, there may be an overhead in using a form (I haven't investigated this) but it will work just as well. The other obvious overhead, of course, is that you always
have one more instance of your class than you really need. There are also some practical problems with using forms instead of classes, which usually crop up when you're doing more advanced things. For example, you won't
be able to set the default property of a form, since it has one already, and you can't make a form public in an ActiveX component. Returning to more conventional methods, Visual Basic 5 introduced Enumerated Types.
Enums can only be numeric (and only Long integers), but we can define them inside classes. This is a good start, because now we define our original exception code inside the class: Public Enum tExceptions
eBadUserName = 32767 End Enum On the surface this is really just an alternative way of doing the following line in a BAS file: Public Const eBadUserName As Long = 32767 However, we're
immediately better off because the definition is inside the class file. A bit of experimentation shows that we can also create more than one enum using the same member names, which is a clue to something even more
powerful. In fact it turns out that although we canīt qualify an enum value with the name of the class in which itīs defined, we can
qualify it with the name of the enum itself. Hence, if we base our enum names on the class names we can get a pretty natural-looking naming convention: Public Enum tCMyClass1 eBadUserName = 32767
End Enum And in use: Select Case Err.Number Case tCMyClass1.eBadUserName: ... End Select |