Recently I realized that VB .NET is less object-oriented than VB 6. Before you bury me under email flames, let me explain.
For example, think about how you draw in VB 6. You pick the object that will draw: a PictureBox, Form, or something else. You set the object's ForeColor, BackColor, FillStyle, DrawWidth, and other drawing properties. Then you call the object's drawing methods such as Line, Circle, and so forth. The following code draws a red ellipse with border width 3, filled with a blue downward diagonal hatch pattern.
Me.DrawWidth = 3
pic.FillColor = vbBlue
pic.FillStyle = vbDownwardDiagonal
pic.Circle (ScaleWidth / 2, ScaleHeight / 2), _
pic.ScaleWidth * 0.45, vbRed, , , _
pic.ScaleHeight / pic.ScaleWidth
Now consider the same operation in VB .NET. First you pick the object on which to draw: again a PictureBox, Form, and so forth. Unfortunately that object doesn't have drawing methods. You need to somehow obtain a Graphics object to do the drawing. How you get the Graphics object depends on when you want to draw. If you are working inside a Paint event handler, it gives you such an object inside an event object. If you are drawing at some other time, you need to use the CreateGraphics method provided by the object you want to draw on (the PictureBox or whatever). (If you get mixed up and use CreatGraphics inside a Paint event handler, the drawing goes fine but doesn't ever appear because it is overwritten by the Graphics object contained in the event handler. This can be a big time waster!)
Next you need to create a Pen object to represent the drawing's line style and color. You may also need to create a Brush object to specify how to fill the thing you're drawing. Finally, you call one of the Graphics object's drawing methods such as DrawCircle, FillCircle, DrawLine, and so forth. The following VB .NET code draws the same ellipse as the previous VB 6 example:
Dim gr As Graphics = Me.CreateGraphics()
Dim ellipse_brush As New HatchBrush( _
HatchStyle.BackwardDiagonal, _
Color.Blue, Me.BackColor)
gr.FillEllipse(ellipse_brush, 0, 0, _
Me.ClientSize.Width, Me.ClientSize.Height)
Dim ellipse_pen As New Pen(Color.Red, 5)
gr.DrawEllipse(ellipse_pen, 0, 0, _
Me.ClientSize.Width, Me.ClientSize.Height)
VB 6 requires 1 object: the PictureBox or Form that will contain the drawing. VB .NET uses 5 objects: the PictureBox or Form that will contain the drawing, possibly an event handler's event object, a Graphics object, a Pen object, and a Brush object. So how can VB .NET be less object-oriented with 5 times as many objects?
The problem is many people forget the goals of object-oriented programming. The general goals are polymorphism, encapsulation, and reusability. Many people list inheritance but that's just a particular way of achieving reusability. (In fact, polymorphism is also a method for increasing reusability but in a more complex way.)
Having more objects is not a goal. If creating more objects was a goal, you could do away with constants such as 37 and 12 and make objects instead. You could create an instance of the 12 object and an instance of the 37 object and then use the 12 object's Plus method to add then two together. In some weird sense, that would be more "object-oriented" but not in a particularly useful way.
They key principle that VB .NET is violating here is encapsulation. You want a class to encapsulate the behavior of the object it represents. If the Car class has a Drive method, you don't want the rest of your program to need to understand how the Drive method works. You just call Drive and the Car Drives.
Now which seems more encapsulated: VB 6 where the PictureBox encapsulates the drawing operation? Or VB .NET where you need to explictly create Graphics, Pen, and Brush objects to draw a simple figure? Throwing all of those extra classes into the mix decreases encapsulation, forcing you to explicitly understand and create those objects every time you want to draw.
In fact, if you're familiar with the underlying GDI function calls that go into drawing operations in Windows, you know that you need pen and brush handles to draw using GDI in VB 6. The Pen and Brush classes simply wrap those objects in the underlying operating system. Not only does creating these objects mean more work for you, it exposes some of the operating system that should remain behind-the-scenes. This gives you more flexibility but at the cost of requiring you to understand the lower-level processes in greater detail. In other words, it weakens encapsulation.
This isn't the only example where VB .NET goes a little overboard. Working with files (and streams), databases, and other areas also require more objects that these tasks did in VB 6. By forcing the programmer to explicitly create these objects, VB .NET reduces encapsulation.
One way to fix this would be to go back to the old VB 6 methods. That's not really necessary. A better solution would be to give these objects defaults behaviors so you wouldn't need to consider the auxiliary classes such as Pen and Brush. If you needed to change those behaviors, you should be able to set properties on the object. For example, the PictureBox object should have a Pen property which is a Pen object defing the PictureBox's line color and style. By default this would probably be a solid black Pen but you could override that if necessary. Similarly the PictureBox object could have a Brush property that defines the fill style and color.
What about the Graphics object? That object can do a lot more than draw on a PictureBox. For instance, it can also draw on a Bitmap or Metafile that isn't attached to any visible object such as a PictureBox or Form. It seems that the Graphics object extracts the common drawing features of PictureBox, Form, Bitmap, Metafile, and other classes that support graphics. That's fine and reasonable, and it probably lets Microsoft reuse code nicely. I wonder, however, if they couldn't have put the Graphics object somewhere in the object hierarchy and let classes such as PictureBox inherit from it. Classes such as PictureBox would encapsulate the drawing process more completely if they provided their own drawing routines rather than requiring you to create an auxiliary Graphics object.
While OOP is the latest fashion these days and has many benefits, it is not beloved by all. For an interesting article explaining why OOP isn't necessarily the greatest thing since paper towels, see this article
Object Oriented Programming Oversold!
Mike Griffiths has this to add:
We have spent the last week trying to convert an existing VB6 program to
VB.NET. We selected a single program that was pretty OO in style as we
thought this might run through the new 2003 conversion mill better than
most. Well we had to pull all of the printing code straight out and then had
come to the same conclusion as you - everything was less object oriented
than the code we had started with.
Just what is the point of a list box without ItemData()? You have to build
that simple functionality yourself!
The new VB6 import routine superficially manages to import control arrays
but we found that things go wrong very quickly - not recommended.
We are now re-building the test program from scratch in VB.NET to see where
that leads us.
I enjoyed the link to the OOP criticism page. Many for points made and part
of my unhappiness with VB.NET is that the baby did get thrown out with the
bathwater. Instead of just enhancing the class building functionality of
VB6, VB.NET swept away all that made the language great for such a wide
variety of program applications. With VB6 we built classes where it made the
code simpler to understand, maintain and implement. We are not sold on
everything being classed based.
I have a project currently in the design stage. The client has decided they
want it done in Java - having dismissed VB6 as outdated and not liking the
look of the .NET setup (before I got anywhere near them as well). It is a
classic business system that will map very well into a relational database -
particularly as some of the relationships are quite complex and overlap. I
have to find a class structure that will allow the same overlaps and
complexity. Classic OOP design is not going to work here and I can't wave a
wand and re-order the real world to suite. Still we working program hacks
are nothing if not pragmatic.
I have posted a new page on the way forward here with links to your new article and the
pages debunking some of the OOP faith. My original rant on "where is VB7"
has been subject to a bit of editing and the revised content is now here.
|