Mind your language

This article was originally published in VSJ, which is now part of Developer Fusion.
While both C# and Visual Basic have each become key development languages for desktop, web and server applications, with each having strengths that appeal to different categories of programmer. But that’s not to say there isn’t room for improvement, and Microsoft have recently enhanced both languages to cope with evolving demands.

Polishing C#

C# is a modern, easy-to-use and powerful object-oriented language. Some might describe it as offering the power of C++ with the ease of use of a RAD language like Visual Basic, but C# is more than the sum of its parts. After a few hours of use you will almost certainly never want to use anything else. With Visual Studio 2005 we now have C# version 2.0, and this raises the question of what the new features might add to an already capable language.

Generics

The biggest new thing in C# 2.0 is Generics, and this single facility really does open new doors. In rough and ready terms a Generic is a class that can be instantiated to a specific type at run time. The problem it solves is the need to rewrite the same algorithm within a class for each type you want to apply it to. For example, how would you write a class that acts as a list of objects of any type? You could write the entire algorithm so that it manipulated Object types and then used casts or reflection as necessary. This is in principle what a Generic class does for you, but there are some important differences of implementation. To implement a Generic list class you simply use List<T> where T is the type parameter. Within List you can use T as if it was a type. When you instantiate an object you provide T with a value such as List <int> and everywhere that T is used within the class it is replaced by int. You can, of course, have multiple type parameters so that your Generic class can be instantiated to work with a specific set of types. Simple and effective, and it’s also efficient.

Java implements its Generics by emulating the way a programmer would create the type specific class. It uses Object types and appropriate casts to create the instance, and this results in a lot of type conversion and boxing/unboxing. C# on the other hand converts the Generic to IL (Intermediate Language) and metadata. At runtime the value of the type parameter is used along with the metadata by the JIT to create an object of the appropriate type. If such an object has already been created, then its code will be shared to create a new instance. Thus the instance of List <int> is really typed to int rather than using a top level type and casts. Because of the runtime typing C# Generics are also arguably an improvement on C++ Templates which are instantiated at compile time and hence not strongly typed in the same way.

Generics are not something that you are going to be using in every single project you work with. Indeed many projects don’t even need you to create new classes, let alone Generics, but whenever you notice that you need the same algorithm applied to different types – think Generic.

Range
Both C# and VB can create the same wide range of projects

Collective improvements

One of the most common uses of Generics is to implement collections, and these are very useful, but they have the reputation for making it difficult for the less experienced C# programmer. The new Iterators in C# 2.0 make it much easier to create custom collections. One of the big advantages of collections is the ability to process them with the help of the foreach loop. This is easy for the client, but when creating a custom collection you had to implement the IEnumerable interface, which also involved keeping track of where the iteration had got to. Not impossibly difficult, and you can still do things this way if you want to, but iterators are much easier. A new keyword, yield, is used to temporarily breakout of an iterator block to supply the value of the next item. The iterator block continues from where it left off when the client foreach loop starts a new iteration.

The simplest example is to use a standard for loop to return each member of a set of numbers 0 to 5 in this case:

class numbers
{
	public IEnumerator
		<int>
		GetEnumerator()
	{
		for(int
			i=0;i<=5;i++)
		{
			yield return i;
		};
	}
}
The effect of the yield return is to temporarily break out of the loop and return the current value of the iteration variable. In the client program this would be used as follows:
private void button1_Click(
	object sender, EventArgs e)
{
	numbers c = new numbers();
	foreach (int t in c)
	{
		MessageBox.Show(t.ToString());
	}
}
It really is this easy. As well as yield return you can also use yield break to terminate an iteration block. Things can be much more sophisticated than this simple example. You can define multiple iterators and iterators with parameters. The enumerator class generated by the compiler takes care of all of the details about where to restart after a yield return. For example you can write:
public IEnumerator <int>
	GetEnumerator()
{
	yield return 1;
	yield return 2;
	yield return 3;
}
Generics plus iterators make it easy for anyone to create reliable custom collections without having to delve into the deeper workings of the system.

Refactoring
New refactoring tools help with code reworking

Elegant code

There are some changes to C# that, while they don’t introduce new features, promise to make code more elegant. The first is the anonymous method – which might seem a little strange when you first meet it. Delegates can be thought of as doing the same job as function pointers in other languages, only in a much safer way. While not difficult to use, it can be irritating and perhaps not always 100% clear to have to first define the method to be used via a delegate, and then to have to setup the delegate. The most common example of this is a simple event handler:
button1.Click +=
	new EventHandler(ButtonClick);
…which adds the method ButtonClick to the delegates that handle the button’s click event. Now you have to go off and write the ButtonClick method. Things are done in this way because in principle you might want to define multiple methods to handle the same click event. If you don’t, it would sometimes be better to simply define the event handler at the same point in the code where it is set up. This is exactly what an anonymous method lets you do. You can now create a delegate by passing it the code needed to implement it. For example:
button1.Click += delegate(
	object sender, EventArgs e)
{
	MessageBox.Show("Click");
}
The code following delegate has access to the variables in the class it is defined in and even to the variable in the method it is defined in. This isn’t the simplest example of defining a delegate because it uses parameters. You can define a delegate with any signature in a fairly obvious way. First define the delegate type:
delegate void Mydel();
Next create the delegate instance:
MyDel Del=delegate()
{
	MessageBox.Show("Called");
};
…and now you can use the delegate:
Del();
As well as being useful when defining event handlers, anonymous delegates can make providing callback functions or creating new threads simpler. They are implemented by the compiler creating additional methods (and even classes) as required, just as you would if you were implementing the delegate in the usual way. Of course, if a delegate is going to be longer than a few lines then you might want to consider defining it in the more traditional way, but for short methods presenting the definition at the point of use can be clearer.

It is also worth mentioning that delegates have become more flexible with the introduction of the idea of co- and contra-variance. Covariance allows a delegate to have a return type that is more specific than the delegate’s signature specifies. This makes it possible for a single delegate type to be used by derived hierarchy of classes. Contravariance allows a delegate to have parameters that are derived from the delegate’s signature types. Again this makes it possible for one delegate type to be used with a larger number of classes.

If anonymous methods are a way to make code easier to read and work with, then partial classes take this even further. C programmers invented the idea of separating a program’s text into a part that rarely changes and a part that is under development, giving the header and source file split. A partial class is similar in the sense that it allows you to split a class definition over more than one source code file. You simply add the modifier “partial” to the class definition, and the compiler automatically tracks down the files needed to obtain a complete class definition. Partial classes are used by Visual Studio to keep automatically generated designer code out of sight and out of harm’s way. When you create a form, the code is split into your part in Form1.cs and Form1.Designer.cs. You might not ever use a partial class, other than those that Visual Studio adds, in your own projects, but they are worth keeping in mind if you design classes that have sections that are under the control of different agents.

As well as major additions, C# 2.0 has a large collection of features that might be considered as minor. Of course what you consider major and minor depends on what you are doing. The compiler now supports both 32-bit and 64-bit environments, for example. You can declare nullable types which support the additional values null, true and false. These make many database-like operations much easier. To create a nullable type you simply use the syntax T?. For example int? is a nullable integer. You can now resolve difficulties caused by namespace collisions using the alias qualifier :: or define an entire class as static so making the singleton pattern easier to implement. You can also control access to properties more finely using access modifiers on, get and set. And my last highlight is the ability to create fixed size and location buffers in unsafe code, which makes calling DLL functions easier.

There are of course many other enhancements to the core C# language, and the compiler in particular, that there isn’t space to mention here. The key point is that they all contribute to making C# a more powerful but practical language. In a nutshell, think of C# 2.0 as a more polished C#.

Intellisense
Intellisense prompting is much improved

Visual Basic 2005 – real RAD

I’ve long been an enthusiastic user of VB6, and I have to admit that I was disappointed by the first version of VB.NET – so much so that I’ve more or less adopted C# (or in extremis Managed C++) for most of my work.

I still occasionally miss VB6 for a number of reasons. It was a rough and ready language, and certainly didn’t have much about it that could be admired for aesthetic considerations. It was also limited in various ways that often resulted in having to employ deep and dirty tricks to get something done. It was a good language for getting projects started, but I have to admit that it was often a poor language for getting them finished. When the first version of .NET appeared on the scene, VB.NET was clearly a capable language, but it seemed to offer few advantages over C#. The syntax might have seemed a little familiar, but it didn’t really hide the fact that VB.NET was no longer a Rapid Application Development (RAD) language. Now, with Visual Basic 2005, things are changing, and I really do think that the latest versions of both VB and C# offer the .NET programmer a real choice. Let me explain…

The trouble with a RAD language like VB6 is that it has to leave out advanced features simply because they might get in the way of the novice programmer. For example, you can’t enforce an object-oriented approach to programming because this prevents a casual approach. But RAD isn’t necessarily the same thing as being casual about creating code. The first version of VB.NET did something that many VB6 programmers had long hoped for. It made VB a fully object-oriented language, but you don’t always want what you wish for. The conversion of VB6 to VB.NET lost many of its RAD aspects. It also raises the question of whether or not a fully object-oriented language with no real limits on what can be achieved could actually be easy to use.

There some new language features in VB 2005, and these deserve discussion. However, it is worth saying that while these are all welcome additions, focusing on them too much would miss the very point of VB. So what is new? As with C#, the main new feature is the provision of Generics. This allows you to write classes that work with any data type you care to specify. You can think of it as passing the class parameters that specify the types that the class will operate on. Generics allow other facilities to be made simpler within VB, such as framework classes that manipulate almost any data type you care to think of, and they certainly aren’t something beginners (or even advanced programmers) are going to use directly in their everyday programming. Still, their presence will be felt by all in one way or another.

There are some technical features which are likely to be more widely used directly. For example, the Continue statement causes any loop to skip to the start of the next iteration. You can create customised events and specify exactly how event handlers are processed. There are some new data types: nullable types are really structures that have fields to accommodate out of range values, i.e. nulls; there are also some additional simple types in the form of unsigned integers of various lengths. It is also possible to specify more precisely the type of access allowed to properties using modifiers on Get and Set. The Using block is typical of the attempt to make writing VB code easier – it automatically disposes of any system resources you might use in the block when your code leaves the block.

All of these and many other changes are handy extras, but there are one or two changes that have greater significance, as they affect the usability of the language far more than you might expect. They are also specific to the VB language, whereas some of the “big” changes such as Generics are shared with C#. Beginners often find it confusing that they have to create a Form class and then an instance of the class. It is perfectly logical, but it can be messy with lots of extra confusing names, and it’s certainly not the way VB6 did it! Now you can create and work with a form without the need for the me keyword or instantiation. For example, if you have created a new class called Form1 you can refer to it using statements like

Form1.Show
Indeed you can refer to any of the methods or properties defined in the Form1 class. If the form doesn’t already exist, VB creates an instance for you without the need for a variable, and you can continue to refer to the instance using the class name. Of course if you want a second instance of the form you have to create an instance and an instance variable for it using the new keyword. What happens is that the compiler automatically generates the instance and substitutes a reference to the instance everywhere the class name occurs. To a C# programmer this sounds messy, but to a RAD programmer it’s perfectly logical in its own way – why proliferate names when you only want a single instance of the class? It is to the point and concise.

Hierarchy
The My objects hierarchy

Another big improvement, this time also shared with C#, is the ability to keep generated and manually written code separate using partial types. One of the initially off-putting features of .NET is that it uses a code generator to implement interactive form editing. VB6 did something similar, but it kept all of the generated form code completely hidden. This made it seem much simpler for the beginner. Now with partial types VB 2005 also keeps its generated code away from the programmer by isolating it in a separate file. What this means is that now the definition of a class could span two or more files, but this is no problem as the compiler automatically gathers the fragmented definitions to create a complete class. The big advantage of this approach over VB6 is that, while you don’t have to look if you don’t want to, the generated code is available for inspection and perhaps even modification.

Perhaps the most important change that affects the use of the language isn’t even strictly speaking part of the language. The key to RAD in an object-oriented world is having the right objects to hand, and this is exactly what the My object library is all about. Notice that these are objects not classes, and they are ready-to-use without the need to instantiate or initialise. You can simply start writing statements that access information about the environment or perform common tasks. There are some powerful facilities such as the TextFieldParser which allows you to read in files containing fixed field structured data, but this would be to miss the point of the My objects. They provide easy access to the simple things that you use all the time. For example, the My.Computer.Clock object gives you the UTC time and the millisecond counter, the My.Forms object gives access to the collection of forms, their properties methods and controls that the application has created and so on. You might think that the problem with this approach to RAD is that the object hierarchy would make it difficult to find out how to achieve some objective without having to spend time doing research. However, the My objects are supported by Intellisense, and given their fairly logical and obvious naming you can usually discover what you need while working. There is also a resource designer that can be used to manage resources such as strings, images, icons, files etc. that the application uses and make them available via the My.Resources object.

There are many other features which in isolation don’t seem particularly important, but all fit together to create a more productive environment. This list includes: edit and continue debugging; IntelliSense filtering; colour highlighting statement completions that will not work in the security zone specified; and the compiler’s ability to suggest and apply corrections to faulty code.

Explore
Simply type My. and the My object hierarchy is presented for you to explore

To see how easy Visual Basic 2005 is to use you really have to try it. There are many small additions and features that I haven’t mentioned, but the important message is that in Visual Studio 2005 you now have a real choice between its two major languages. Visual Basic is no longer just C# using slightly different syntax; it is a language suitable for RAD use in the long tradition of Basic.

Some of its new features might make purists unhappy, but they are effective in getting an application off the ground. Given careful design within an object-oriented environment, Visual Basic 2005 now provides a safe approach to RAD that promises not to run out in the later stages of the project. We can only hope that the differentiation started in 2005 between C# and VB continues to develop in future versions.


Dr Mike James, editor of VSJ, has over 20 years of programming experience, both as a developer and lecturer. He has written numerous books and articles on programming, and his PhD is in computer science.

You might also like...

Comments

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“The generation of random numbers is too important to be left to chance.” - Robert R. Coveyou