Post

Visual Basic 8.0 Language Enhancements

In addition to the myriad of new features being added to the Visual Basic (Visual Studio) IDE and the .NET Framework, there are several enhancements to the core language. Some of these have been publicized quite heavily such as generics, partial types and IsNot while others not so much.

This article is a based on the Beta 2 release of Visual Studio .NET 2005.

Partial Types (aka Partial Classes)

On the surface, this feature appears to be added to benefit Microsoft than the end developer. Especially given the following text in the documentation:

Under normal circumstances, you should not split the development of a single class or structure across two or more declarations. Therefore, in most cases you do not need the Partial keyword.

However, digging deeper, you’ll find that there is at least a few invaluable uses that partial types provide. If you’re like me and prefer the one class one file approach, you’ll come to appreciate this feature. But you’re saying to yourself, “I already do this”. Not saying that you don’t, but what happens when you want to defined a class that will be contained within another class? In VB7/7.1, you’d have a class defined in a file and it would contain the inner class. Using partial types, you can now place each of these classes in their own files and, upon compilation, these multiple files would be combined together.

ClassA.vb

1
2
3
Partial Public Class ClassA
 ' Implementation of ClassA
End Class

ClassInner.vb

1
2
3
4
5
6
7
Partial Public Class ClassA

  Private Class ClassInner
    ' Implmentation of ClassInner
  End Class

End Class

ClassInnerInner.vb

1
2
3
4
5
6
7
Partial Public Class ClassInner

  Public Class ClassInnerInner
    ' Implementation of ClassInnerInner
  End Class

End Class

I’m not sure if I will move to this model or not, but it’s interesting to consider.

Another use of partial types is in regards to code generation tools. You could have a base portion of the class that would always be used no matter the target. You could then have a secondary file (or possibly more) that would contain the code generated by external tools such as CodeSmith whenever you target the class to another customer (for example).

ClassA.vb

1
2
3
Partial Public Class ClassA
  ' Partial implementation of ClassA
End Class

ClassACodeGened.vb

1
2
3
4
5
6
7
Partial Public Class ClassA
  
  ' Partial implementation of ClassA created 

  ' using a Code Generation tool.

End Class

This next usage of partial types is one that I’ve seen no one discuss. When writing code that requires late binding, you can turn off Option Strict. However, this is at the class level and penalizes all of the code in the containing class by running a little slower (performance) and late binding code can be a potential bug farm. Utilizing partial types, you can define a part of your class as being type-safe and another portion of the class can allow late binding. This way if you only have a few lines of code that require late binding, you can isolate those in a secondary file (using partial types) and the rest of the code is using strict typing rules.

ClassA.vb

1
2
3
4
5
6
7
8
9
10
11
Option Explicit On
Option Strict On
 
Partial Public Class ClassA
 
  Public Sub TestStrictOn()
     Dim s As String = 1 '<--- Option Strict On 
                         '     disallows implicit conversions.
   End Sub
 
End Class

ClassALateBind.vb

1
2
3
4
5
6
7
8
9
10
Option Explicit On
Option Strict Off
 
Partial Public Class ClassA
 
  Public Sub TestStrictOff()
    Dim s As String = 1
  End Sub
 
End Class     

As I said, on the surface it appears that this feature was created to benefit Microsoft to protect the code generated by the IDE designers from being mangled by the end developer. Although it is true that this code being placed in a partial type does benefit the developer by creating a cleaner working environment, you can see after further investigation that there are many other benefits to what partial types can provide you as an end user of this keyword.

Default Instances

Default Instances are probably one the most controversial additions to VB8. There seems to be a small (but very verbal) group of people who seem to believe that this feature represents all that is “evil” in the world of classic Visual Basic. I on the other hand, after giving them a run through, welcome their return. Could they be used inappropriately? Sure. However, anything can be used inappropriately. At the end of the day, is it a useful and productive tool to have in your arsenal? This is a definite yes. A few key points that I think several of these individuals forget:

  • This feature is one of the reasons why Visual Basic 1.0 to 6.0 became the most widely used development language in the world. It makes writing Windows applications easy.
  • Although similar in concept to what was contained in previous versions of Visual Basic, there are some significant changes. One of which is being able to actually test to see if a form exists without it creating the form upon you testing for its existence.
  • This feature was targeted for release with VB.NET 7.0, but was delayed for various reasons.

OK, now that that is all out of the way, what exactly are default instances? In order to understand what default instances are, let’s walk through a quick development experience. You create a new Windows Form application. You add a few controls, set your properties for the form (Form1) and the controls. Double click on the controls and add code. You press run on the tool bar. The application starts up and it’s running. You wrote no code.

Exit the application and add a Browse for File dialog control. Give it a name and set its properties. Add a button. Double click on that button and tell the file dialog to become visible by typing:

1
2
3
4
5
6
7
8
9
Private Sub Button1_Click( _
  ByVal sender As System.Object, _
  ByVal e As System.EventArgs) Handles Button1.Click

  If OpenFileDialog1.ShowDialog = DialogResult.OK Then

  End If

End Sub

Again, not a whole lot of code. Run the application again and you get what you expected. Now after looking though the existing common dialogs, you find that what you want doesn’t exist. So now it’s time for you to create your own so you add a new form to your project. How do you get that form to show? You could instantiate an instance of that control and then call upon the ShowDialog method as you did with the OpenFileDialog or utilizing Default Instances, just write code that is very similar.

1
2
3
4
5
6
7
8
9
Private Sub Button1_Click( _
  ByVal sender As System.Object, _
  ByVal e As System.EventArgs) Handles Button1.Click

  If Form2.ShowDialog = DialogResult.OK Then

  End If

End Sub

OK, I hear what you’re thinking. But that’s only saving one line of code. This is true for this example, but the implications are far greater. Going back to the example I walked you through, Default Instances brings consistency to the design of Visual Basic, Windows Forms and the RAD design experience. By default, your main form doesn’t get instantiated by you, the developer. Rather that is handled by the application startup. You could control this by adding your own Sub Main(), but it was not necessary unless you had a specific need. (It’s still not necessary with the addition of the Application Framework, but that’s another topic.) In addition to making it easy to show a Form, sharing information across various forms is also made extremely simple. Since the accessibility of these Default Instances are at the application level, you can access the Public/Friend methods, properties and components from anywhere within your application.

Using Statement

Before I get into the details of the Using statement, let’s look at an example.

1
2
3
4
5
6
7
8
9
10
11
  ' Open a file.
  Dim fs As New IO.FileStream("c:\text.txt", IO.FileMode.Open)
  Try
    ' Do some file based tasks.
    fs.Seek(0, IO.SeekOrigin.Begin)
    fs.Seek(0, IO.SeekOrigin.End)
  Finally
    ' Using Finally, we are sure that the file will close
    ' even if an error where to occur.
    fs.Close()
  End Try

Using this code, you can see that you need to wrap the actual code that will manipulate the file (upon successfully opening the file) so that if an error were to occur, you are sure that the file would close by placing the close within the Finally block. Wouldn’t it be nice if there were an easier way to accomplish this?

1
2
3
4
5
6
  ' Open a file.
  Using fs As New IO.FileStream("c:\text.txt", IO.FileMode.Open)
    ' Do some file based tasks.
    fs.Seek(0, IO.SeekOrigin.Begin)
    fs.Seek(0, IO.SeekOrigin.End)
  End Using

Using works in much the same way as the previous example utilizing the Finally block. There are a few differences, but overall you can think of it from the same conceptual standpoint. There are three parts to the using statement; acquisition, usage and disposal. Acquisition relates to the Using portion of the block. This is the area where you define (and create) the object (or objects, separated by commas) to be used. Usage is the actual section between the Using and End Using block. Disposal occurs at the End Using portion of the code block. Just as Finally would occur whether an error occurred, so will the Disposal portion of the Using block. One difference to note is that of scope. Since the object is defined and created within the Using block, it’s only accessible from within the Using block.

Not only do you reduce the number of lines you have to write, you significantly improve the applications overall robustness by making sure that you dispose any objects that implement IDisposable just by utilizing Using. This is especially true if you need to write code containing multiple nested Using statements. The same nested code written using Try/Finally is insanely more complex in comparison.

Mixed Access Levels for Properties

You now have more finite access control when defining properties for your classes. In VB7/7.1, you could only control the access level at the property level. In addition to specifying the access level at the property level, VB8 allows you to split this across the Get and Set portion of the property.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Public Class Employee
 
  Private m_salary As Double
 
  Protected Property Salary() As Double
    Get
      Return m_salary
    End Get
    Private Set(ByVal value As Double)
      m_salary = value
    End Set
  End Property
 
End Class

Unsigned Types

This one is near and dear to my own heart. This version marks the first release of a BASIC product from the walls of Microsoft (that I’m aware of) that provides for full support for unsigned types (UShort, UInteger and ULong). What would you use them for? To be honest, not a lot of people need to utilize unsigned types; however, those that do need them will be very excited. Three areas where unsigned types are very necessary are binary file I/O, bit shifting and P/Invoke. Of the three, bit shifting is probably the most useful to a wide variety of developers. Bit shifting allows you to easily read/write bits to a value. Having unsigned types allows you to have values that don’t have a signed bit to control positive and negative values; thus allowing you access and control of all of the bits. So for example, rather than have an array of days (or a collection), you could use an Integer and utilizing the bits to represent a set of 32 bits (giving you 32 Boolean values). You could have 12 of these taking up a total of 384 bytes. The same storage using an array of Booleans would consume 730+ bytes (each Boolean is 2 bytes in size). This is just one example, there are many, many more.

Unsigned types also allow you to better conserve memory by allowing you to utilize types that can handle positive values in a lesser amount of memory. For example, if you have a value that will only be represented as a positive number and is between 4,294,967,295 but could exceed 2,147,483,647 (the maximum positive value of an Integer), you could use a UInteger (32 bits) instead of having to using a Long (64 bits).

One not of caution concerning unsigned types is that they are not CLS-compliant, so their use is pretty much restricted to internal usage only; meaning that you shouldn’t expose methods, properties, etc. in reusable components that could be utilized by languages other than VB (or C#).

In an honorable mention sort of way, SByte also makes its debut as well. To be honest, I don’t have a clue how you would use such a variable type, but hey, I suppose it’s there just in case.

Continue Statement

VB8 introduces the new Continue statement that enhances the Do/Loop, While/End While, and For/Next constructs. By using the Continue For/Do/While statement, the execution of the current pass immediately exists and begins the next pass.

1
2
3
4
5
6
7
8
  For i As Integer = 1 To 100
    If i > 5 AndAlso i < 20 Then
      ' Skip over the rest of the processing inside of the loop 
      ' and start the next iteration. 
      Continue For
    End If
    ' Execute some other code. 
  Next

Although the addition of this may not drastically change your coding world, I’m sure you’ll find that it will help you reduce the amount of code you write and improve overall readability.

Although I’m positive I’m not the only reason that the Continue For/Do/While statement was added; I can say that my name is (or at least should be) officially tied to it as being one of the individuals who submitted a wish to have it added, if for nothing more than being a +1 to have the feature added. So if you don’t like this being added or its implementation, feel free to blame me. ;-)

IsNot Operator

Although not a significant enhancement, the IsNot operator does help to make code a bit cleaner and more natural to read. So instead of:

1
2
3
  If Not s Is Nothing Then
    ' Do something...
  End If

You could (or should I say should) write it as:

1
2
3
  If s IsNot Nothing Then
    ' Do something...
  End If

For me, the verdict is still out on this one. I’ve gotten pretty used to writing using the previous style, so only time will tell if I’m a convert or not.

Operator Overloading

VB8 now includes the capability to define your own operator behaviors for your custom classes. Pretty much covers any of the operators which include =, +, -, <, >, Mod, And, Or and Like. To test this, you could add the equal and greater/less than operators to a form (Form2).

1
2
3
4
5
6
7
8
9
10
11
12
13
  Public Class Form2

    Public Shared Operator =(ByVal x As Form2, _
                            ByVal y As Form) As Boolean
      Return TypeOf y Is Form2
    End Operator

    Public Shared Operator <>(ByVal x As Form2, _
                              ByVal y As Form) As Boolean
      Return Not TypeOf y Is Form2
    End Operator

  End Class

Now that Form2 has the added support for these operators, from Form1:

1
2
3
4
5
6
7
  Dim f As New Form2
  If f = Form2 Then
    ' Equal.
  Else
    ' Does not equal.
  End If
  f.Dispose()

Generic Types (aka Generics)

might add more here after additional experimentation

I’m not going to go into too much detail here on generic types since just about everyone else seems to be talking about them. What I will say is that generics are going to become a tool that you will use often. Whether you create generic classes yourself, using the ones in the Fx libraries or utilizing much of the new functionality that My provides; it will be difficult for you to avoid generics to any degree.

Custom Events

need to explore this one deeper before writing about

This post is licensed under CC BY 4.0 by the author.