More About Properties
Let’s talk about properties. The syntax for using properties looks exactly the same as the syntax for using member fields of a UDT. But in fact, a property is very different from a UDT field.
Essentially, a property looks like a procedure to the implementor, but works like a variable to the user. The purpose of using property procedures rather than just giving the world access to internal variables is two-fold. You can validate the input data you receive from users, and qualify or process output data before giving it out to users. Another advantage is that procedures abstract data so that you can change the implementation without breaking client code.
Every object-oriented language has this problem, but most of them have a less elegant solution. C++ and Java, for example, depend on conventions such as always using Get and Set in the names of access methods.
c = thing.GetCount(); // C++ or Java access internal data
thing.SetCount(c + 6);
But in the Basic philosophy, the details of data protection should not affect clients. They shouldn’t have to use an unnatural syntax in order to be protected.
Instead, Visual Basic allows you to protect internal data with property procedures—Let, Get, and Set. The classic Get/Let property pair looks like this:
Private sStuff As String
§
Property Get Stuff() As String
‘ Qualify or process data output here
Stuff = sStuff
End Property
Property Let Stuff(sStuffA As String)
‘ Validate data input here
sStuff = sStuffA
End Property
There are lots of ways to validate data. But what if you have data that just doesn’t need validation? This often happens with Boolean properties. How are you going to come up with invalid input for a Boolean? By definition, everything is either True or False. Sometimes strings are the same way; if empty and null strings are valid for your property, then there probably isn’t any need to validate them. Visual Basic provides a shortcut for defining properties that can’t go wrong:
Public Stuff As String
This syntax makes Stuff appear to be a data member of the class in the same way that a field is a data member of a UDT. This is an illusion. Don’t expect to get any noticeable speedup from using a Public property instead of a property procedure. What the syntax means is that Visual Basic will generate the property procedures for you behind the scenes. In the COM standard on which Visual Basic is based, all access to objects is through procedures.
Technically, property procedures are also an illusion. What you really get with a property procedure is something that would look more like this if you could write it in Visual Basic:
Private sStuff As String
§
Function GetStuff(sStuffRet As String) As HResult
sStuffRet = sStuff
GetStuff = 0 ‘ Always return error code or 0 for success
End Function
Function LetStuff(sStuffA As String) As HResult
sStuff = sStuffA
LetStuff = 0 ‘ Always return error code or 0 for success
End Function
Visual Basic with Curly Braces
If Visual Basic is your mother tongue or if you have real work to do, you can skip this sidebar. On the other hand, if you enjoy seeing people make fools of themselves in public, you might want to watch me try to prove that Java and Visual Basic are twins, separated at birth, while C++ isn’t even the same species.
To make this difficult argument, I’ll ask you to put aside the issues that language aficionados normally argue about. I don’t care whether the type or the variable comes first. Perhaps Dim is the worst keyword name ever; maybe it’s typedef. Should blocks be enclosed in curly braces or terminated with an End statement? Who cares? Are free-format languages better than line-oriented languages? Leave it to the lawyers.
What really matters is how memory is allocated and used. For example, here’s how you declare object variables in Visual Basic:
Dim thing As CThing ‘ VB declare object variable
This is similar to a C++ pointer variable, which you create like this:
CThing * pthing; // C++ declare object pointer variable
Java, like Visual Basic, has no pointers. Object variables are created like this:
CThing thing; // Java declare object variable
Java and C++ might look similar, but that asterisk in the C++ declaration makes a world of difference. In what really counts, Visual Basic and Java are the same.
All of these statements create a reference to a theoretical object, but none of them actually creates a CThing object. The Visual Basic statement creates a variable initialized to Nothing. The Java statement does something equivalent. The C++ statement creates an uninitialized variable. The big difference is that accessing thing in Visual Basic or in Java results in a polite, predictable error, while accessing an uninitialized C++ pointer variable fails rudely and unpredictably.
You can’t create an object directly in Visual Basic or Java, but you can in C++:
CThing thing; // C++ declare object
This C++ statement creates a CThing object in memory. Notice that it looks the same as the Java statement shown earlier, but it means something quite different. It works more like a Visual Basic UDT, except that it can have methods as well as data members. You can start calling its methods immediately after you declare it. Some of you (such as those who read the mistaken claims in the last edition of this book) might say that the following Visual Basic variable is equivalent:
Dim thing As New CThing
Not at all. This is just a shortcut that creates an object variable, but delays automatic creation of it to a later time. If you want to create an object from an object variable, you do it like this in Visual Basic:
Set thing = New CThing ‘ VB creates object
Set creates a CThing object and connects it to the thing variable, and disconnects the thing variable from the object it was previously connected to.
The equivalent Java statement is similar, except that there’s no Set:
thing = new CThing(); // Java create object
The nearest equivalent in C++ is this:
pthing = new CThing; // C++ create object and point to it
The C++ new operator allocates storage for a class in much the same way that New does in Visual Basic or new does in Java. The difference is that you have to use the delete operator to get rid of that storage in C++. Visual Basic and Java do the cleanup (sometimes called garbage collection) for you.
At this point you can use the thing variable as if it were a CThing object. You can call the CThing object’s methods and use its properties:
thing.Square()
That’s the Visual Basic version (the parentheses are optional). The Java version is the same except it needs a closing semicolon. But C++ can create either a pthing pointer variable or a thing variable. These two versions need a different syntax to distinguish them.
thing.Square(); // C++ variable containing an object
pthing->Square(); // C++ variable pointing to an object
And that’s not even mentioning a third possibility, a C++ reference variable which looks like an object and works like a pointer to an object. But we won’t get
into that.
I could continue with this comparison, but it would come to more of the same. Java looks like C++, but acts like Visual Basic. There are two kinds of languages, and the thing that separates them is their attitude toward pointers. C++ embraces and honors them. Java refuses to recognize their existence. Visual Basic—well, pointers seem to have squeezed a foot in the door, but only in relation to the Windows API. In the difference that matters most, Visual Basic and Java are on the same side.
Behind the scenes, property access would actually look something like this:
On e <> 0 Goto EHandler
‘ iLine = txtNote.Line
e = txtNote.GetLine(iLine)
‘ txtNote.Line = iLine + 1
e = txtNote.LetLine(iLine + 1)
§
EHandler:
HandleError e
Fortunately, Visual Basic handles these bookkeeping details so that you don’t have to worry about them.