Und VB .NET hat doch einen Sinn

Veröffentlicht: 11. Dez 2001 | Aktualisiert: 19. Jun 2004

Von Ralf Westphal

Seit Vorstellung des .NET Framework hat C# viel Aufmerksamkeit auf sich gezogen. VB .NET hingegen ist in der Diskussion darum, welche Sprache für .NET-Entwicklungen benutzt werden sollte, nicht gut weggekommen. Das ist schade, denn VB .NET ist ein echtes Produktivitätswerkzeug.

Auf dieser Seite

 MSDN Kolumne Dezember 2001
 Prioritätenverschiebung
 VB .NET Produktivitätsfeatures
 Was zu vermissen ist
 Was zu vermeiden ist
 Fazit

MSDN Kolumne Dezember 2001

Bild01

In meiner April-Kolumne "Die Qual der Wahl der Sprache" hatte ich mehr oder wenig explizit eine Lanze für C# gebrochen. Aus der VB6-Welt kommend war ich als "alter C/C++-Programmierer" erfreut, in einer vertrauten Notation das Positive aus verschiedenen Welten in C# vereint zu finden:

  • C# verzichtet (zunächst) auf C/C++ Zeigerkonstrukte und ist damit im Grunde so einfach und geradlinig wie VB

  • C# bietet einige ausgefeiltere Features im Vergleich zu VB

  • C# ist die Sprache des .NET Framework und zur Standardisierung eingereicht

Etwas ermüdet vom jahrelangen Kampf mit VB6 gegen Limitationen in Bereichen wie COM, Multithreading usw. erschien mir C# als die bessere Alternative im Vergleich zu VB .NET. Mein Präferenzpendel schwang sozusagen von der VB-Seite zurück zu C/C++. Dazu stehe ich nachwievor und finde meine Reaktion auch heute noch verständlich. C# hat für mich auch immer noch die damals betonten Qualitäten. Und ich finde weiterhin wichtig, C# lesen und schreiben zu können. Eine Fertigkeit, die jedem .NET-Entwickler gut ansteht (- wie auch übrigens die intensivere Auseinandersetzung mit der Intermediate Language (IL)).

 

Prioritätenverschiebung

Seit April sind nun allerdings einige Monate ins Land gegangen, in denen ich Gelegenheit hatte, mich sowohl mit C# wie auch mit VB .NET zu beschäftigen. Meine Meinung zu VB .NET hat sich dadurch erheblich gewandelt. Im direkten Vergleich der üblichen Features mag VB .NET immer noch ein wenig unterlegen sein. Und natürlich spielt VB .NET immer noch eher "die zweite Geige" bei Microsoft. Darum geht es mir aber nicht mehr so sehr. (Ebensowenig um die Kompatibilitätsdefizite im Bezug auf VB6.)

Vielmehr hat sich meine erneute Zuneigung zu VB an weniger beachteten Eigenschaften entzündet. Operator Overloading in C# ist eine schöne Sache, die ich nicht missen möchte. Aber wie oft brauche ich sie wirklich? Entscheidender ist für mich, in welcher Sprache ich produktiver bin. Mit welcher Sprache erzeuge ich schneller 80% meines Codes? Meine Antwort darauf lautet: VB .NET.

 

VB .NET Produktivitätsfeatures

Ein solcher "Sinneswandel" verlangt natürlich nach einer Begründung. Im Folgenden möchte ich Ihnen daher einige VB .NET-Features vorstellen, von denen ich meine, dass sie VB .NET derzeit zu dem .NET-Produktivitätswerkzeug machen.

Case Insensitivity
In VB .NET-Code ist die Groß-/Kleinschreibung unerheblich. Die Deklaration

Dim a, A as Integer

ist fehlerhaft, da sich aus Sicht von VB .NET die beiden Variablennamen nicht unterscheiden. In C# hingegen deklarieren Sie mit

int a, A;

zwei unterschiedliche Variablen.

Warum soll diese Toleranz von VB .NET gegenüber der Groß-/Kleinschreibung Sie nun aber produktiver machen? Weil beim Eintippen von Variablennamen usw. weniger "geistiger Aufwand" nötig ist. Sie müssen einfach weniger nachdenken. Sie müssen weniger Fehler korrigieren, weil Sie sich doch wieder nicht an die richtige Schreibweise eines Namen erinnert haben.

Intellisense bietet zwar auch in C# Unterstützung bei der Auswahl von Namen - z.B. können Sie "thread" + Strg-Leerzeichen eingeben und stehen in der Intellisense-Liste auf "Threading" -, doch das funktioniert nur, solange ein Name nicht vollständig ist. Haben Sie erst einmal "threading" ausgeschrieben, dann warten Sie vergeblich auf eine Liste der Typen im Namespace System.Threading. VB .NET ist hier viel toleranter - und macht Sie schneller.

Freunde von C/C++/C# mögen die Case sensitivity von C# positiv hervorheben, vergrößert sie doch den Namensraum und erlaubt eine feinere Differenzierung - am Ende muss man sich jedoch Fragen, ob diese Vorteile nicht teuer erkauft sind. Man könnte vielmehr argumentieren, dass subtile Unterschiede in der Groß-/Kleinschreibung von Namen mehr Verwirrung denn Nutzen stiften, da sie selbst keine Information über quasi beliebige Konventionen hinaus transportieren. (Man könnte z.B. vereinbaren, dass Variablen immer mit Kleinbuchstaben beginnen müssen und Methoden mit Großbuchstaben. Dann könnte es in C#-Code Variablen und Methoden mit gleichem Namen geben.)

Der Grund dafür, dass auch C# Case sensitive ist, liegt vielmehr in der Tradition: C ist Case sensitive, C++ auch und ebenfall Java. Bei C als erster Sprache in dieser Reihe war der Grund aber wahrscheinlich weniger der Wunsch nach mehr Raum für Subtilitäten in der Namensgebung, als vielmehr der Geschwindigkeitsvorteil bei binären Zeichenkettenvergleichen in den ersten C-Compilern. Warum sollte eine Sprache heute darunter jedoch noch "leiden" müssen?

With
Sprache gewinnt oft an Verständlichkeit, wenn man einen "Kontext" aufbaut. Im Satz "Peter ging zur Bank, löste einen Scheck ein und kaufte Blumen" bildet die Person Peter den Kontext für die Scheckeinlösung und den Blumenkauf. Wir wissen durch den Satzbau einfach, dass sich diese Nebensätze ebenfalls auf Peter beziehen. Es ist nicht nötig zu schreiben "Peter ging zur Bank, Peter hob Geld ab und Peter kaufte Blumen." Sprache, die weniger mit solchen Kontexten arbeitet, um mehr Genauigkeit zu erzielen - z.B. das typische Juristendeutsch -, wirkt aufgebläht und ist schwerer verständlich.
Gleiches gilt auch für Programmiersprachen. Sourcecode ist oft schwerer als nötig verständlich, weil er nur begrenzt Kontext im obigen Sinne bietet. Eine Form von Kontext ist der Gültigkeitsbereich:

class Person 
{ 
private string _nachname, _vorname; 
public string name 
{ 
get 
{ 
return _vorname + " " + _nachname; 
} 
} 
}

Die Member-Variablen der Klasse sind im get-Accessor sichtbar und ohne weitere Qualifikation ansprechbar. Die Klasse bzw. das aktuelle Objekt, auf dem die Property name aufgerufen wird, ist der Kontext.

Eine andere Art Kontext stellen instrinsische Variablen wie me, this, MyBase usw. dar. Aber auch sie sind durch die Sprache vorgegeben.
Unter Microsofts .NET-Sprachen bietet lediglich VB .NET eine Möglichkeit, jederzeit einen beliebigen Kontext aufzubauen. Mit der With-Anweisung können Sie ein Objekt zum Bezugspunkt für abgekürzte Member- und Methodenaufrufe machen:

With New OleDb.OleDbCommand() 
.Connection = myconnection 
.CommandText = "insert ..." 
.CommandType = CommandType.Text 
.CommandTimeout = 100 
.ExecuteNonQuery() 
End With

In C# müssten Sie eine Hilfsvariable deklarieren und in jeder Zuweisung wiederholen. Das erhöht die Lesbarkeit nicht und ist wiederum umständlicher und damit langsamer beim Schreiben, als eine With-Anweisung.

Warum C# keine ähnliche Möglichkeit bietet, Kontext aufzubauen, ist unverständlich. Ebenso, warum VB .NET auf With beschränkt ist. Microsoft Research hat Anfang des Jahres 2000 ein Paper veröffentlicht (Tod A. Proebsting, Benjamin G. Zorn, Programming Shorthands, 19. Jan. 2000), das die Vorteile solcher Konstrukte deutlich erklärt. Das Bewusstsein ist also grundsätzlich vorhanden.

Variablendeklaration
Auch wenn es nicht den Anschein haben mag, so fördert die VB-Syntax auch die Produktion kurzen Codes. Bei einer IF-Anweisung

If ... Then 
... 
End If

gilt das nicht, wenn Sie das C#-Equivalent im Hinterkopf haben:

if(...) { 
... 
}

Aber bei Deklarationen. Vergleichen Sie einmal die VB .NET-Deklaration

Dim conn As New OleDbConnection("...")

mit ihrem Pendant in C#:

OleDbConnection conn = new OleDbConnection("...");

In VB .NET können Sie eine Objektvariable gleichzeitig mit einem Typ versehen und eine Instanz erzeugen. Eine Praktik, die durch VB6 - zuunrecht - in Verruf geraten war, weil dort die Objekterzeugung erst beim ersten Aufruf einer Methode wirklich stattfand. In VB .NET entspricht die obige Deklaration jedoch der umständlicheren:

Dim conn As OleDbConnection 
conn = new OleDbConnection("...")

Ohne (vermeintlichen) Nachteil, stellt die Möglichkeit zur kompakten Deklaration+Instanziation von Variablen also einen klaren Vorteil von VB .NET gegenüber C# dar. Sie sparen Tipparbeit. Probieren Sie es einmal aus.

Auto-Statementcompletion
Bei den Deklarationen ist die VB .NET-Syntax der von C# in ihrer Kürze überlegen. Bei Befehlen wie If, While oder auch Function jedoch nicht, wie Sie oben schon gesehen haben. C# setzt auf eine klare Blockstruktur mit {} als Klammerpaar. Das ist in seiner Knappheit kaum zu schlagen und C#-Code sieht daher oft "dünner" und vielleicht auch übersichtlicher aus.
Syntaxdefinitionen in C# werden durch diese Art Anweisungsblöcke sehr einfach gemacht. Hier eine etwas laxe Definition zweier C#-Anweisungen in EBNF:

ifStatement ::= "if" "(" expression ")" statement [ "else" statement ]. 
forStatement ::= "for" "(" ... ")" statement. 
statement ::= ... | "{" statementlist "}". 
statementlist ::= statement { ";" statement }.

Sowohl die Anweisungen innerhalb eines if- wie eines for-Statement werden durch das Symbol statement repräsentiert. Und statement kann entweder eine Anweisung oder ein in {} eingeschlossener Anweisungsblock sein. Da schlägt das Herz jedes Programmiersprachentheoretikers höher.Von einem pragmatischen Standpunkt aus betrachtet, ist die C#-Philosophie (und damit die von C, C++, Java und auch Pascal) aber suboptimal: Weil aus der Syntaxdefinition nicht eindeutig abgeleitet werden kann, ob auf ")" in den obigen Definitionen nur eine Anweisung oder ein Anweisungsblock folgt, kann der C#-Codeeditor in VS .NET Sie weniger gut bei der Codeeingabe unterstützen als der von VB .NET.
Geben Sie einmal folgendes in einem C#-Programm ein und drücken dann <Enter>:

if(1<2)

Es passiert: nichts. Es wird kein {} ergänzt. Sie müssen selbst an den Anweisungsblock denken. Tragen Sie anschließend ein {} nach, springt der Cursor auch nicht in den Anweisungsblock.
Wenn Sie dagegen in einem VB .NET-Programm Folgendes gefolgt von <Enter> eingeben

if 1<2 then

dann trägt VS .NET selbst das End If nach und stellt den Cursor in die Anweisung. Aufgrund der Syntax von VB .NET, die konkrete Schlüsselworte zum Schließen von Anweisungen vorsieht, die mehrere Statements enthalten können, kann der Codeeditor Ihnen mehr Arbeit abnehmen.
Das mag gerade eingefleischten C/C++/Java/C#-Entwicklern als geringer Vorteil erscheinen. Wenn Sie jedoch eine Weile mit VB .NET gearbeitet haben und dann zurück gehen zu C# oder auch VB6, werden Sie merken, welchen Segen die Auto-Statementcompletion darstellt. Sie werden Sie nicht mehr missen wollen, genauso wie die automatische Einrückung von Code. Mit Auto-Statementcompletion können Sie sich mehr auf den Inhalt konzentrieren, als auf die Form Ihres Codes. Und Sie sind einfach schneller beim Schreiben.

Autoformatierung
Ein weiterer Vorteil des VB .NET-Codeeditors ist seine Hilfe bei der Codeformatierung. Code soll ja nicht nur korrekt sein, sondern auch übersichtlich und lesbar. Dazu gehört sicherlich die einheitliche Einrückung von Anweisungen. Dazu gehört aber auch die allgemeine Anordnung von Anweisungsbestandteilen.
In C# können Sie vielfach Code formatieren, wie Sie wollen. Die folgenden Zeilen bleiben exakt so in Ihren Quellen, wie Sie hier stehen:

int x, y=1,z = 2; 
x=0; 
y = 1; 
z  =2;

Daran ist nichts falsch. Wenn Sie jedoch Code verschiedener Entwickler betrachten, dann summieren sich die subtilen Unterschiede in der Schreibweise (insbesondere der Gebrauch von Leerzeichen) zu deutlich schlechterer Lesbarkeit auf.
Demgegenüber "bevormundet" der VB .NET-Codeeditor Sie mehr. Wenn Sie eine Zeile mit <Enter> abschließen, formatiert er sie einheitlich. Die Schreibweise von Namen wird der bei Ihrer Definition angepasst und "überflüssige" Leerzeichen entfernt. Aus

dim s  As inTeger=0

wird

Dim s As Integer = 0

Diese "Bevormundung" dient zwei Zielen: Zum einen macht sie den Code besser lesbar, zum anderen verringert sie Ihren geistigen Aufwand beim Eintippen. Sie müssen sich weniger kontrollieren, sind schneller und können doch sicher sein, dass am Ende lesbarer Code herauskommt.
Freunde von C# werden hier einwänden, dass Sie die geringeren Eingriffe des C#-Editors schätzen, da Sie so mehr Freiheit bei der Formatierung haben. Ein auf den ersten Blick valider Punkt, dem ich - leider ohne Möglichkeit zur Diskussion an dieser Stelle - entgegenhalten würde, er sei in der Vergangenheit stark überschätzt worden. Die Formatierung von Code ist der falsche Ort zum Ausleben von "Kreativität" und "Individualität".
Automatische Codeformatierung verliert nach kurzer Zeit auch ihren Schrecken: Die Aufmerksamkeit wird vom Unwesentlichen - dem Wie - zum Wesentlichen - dem Was - gelenkt.

(Überspitzt ließe sich vielleicht sogar sagen: Dass wir überhaupt noch Anweisungen in Form von Text aneinander reihen, ist ein Anachronismus, der einzig einem Mangel an vernünftigen Alternative z.B. im graphischen Bereich geschuldet ist. Gerade bei Anweisungen, die aus einer Kombination von Symbolen bestehen, ist es eigentlich nicht einsichtig, warum wir sie alle eintippen müssen. Ein Tastendruck könnte eine Struktur wie If-Then-Else-End If aufbauen und den Cursor hinter das If rücken. Oder er könnte eine andere Form der Anweisungsrepräsentation erzeugen. Am Ende wäre es dann nur nötig, Ausdrücke (und vielleicht Variablendeklarationen) von Hand einzutippen. Wieviel schneller könnte die Produktion von Code dann sein - ohne Formatierungsfreiheiten?)

Eventhandling
Produktivität, wie ich sie hier verstehe, ist ein Resultat aus Werkzeugunterstützung und Spracheigenschaften. Beides kommt sehr vorteilhaft in der Ereignisverarbeitung von VB .NET zusammen. Ereignisse sind ein praktisches Programmierkonzept für alle Fälle, in denen Code Rückmeldungen geben soll an seinen Aufrufer oder eine beliebige Anzahl interessierter "Parteien". Während dies früher auf den Umgang mit Steuerelementen beschränkt war, hat VB5 das Programmiermodell allgemein auf Klassen ausgedehnt. Daran hat sich mit VB .NET nichts verändert. Hier ein Stück Beispielcode:

Class Processor 
    Event OnProgress(ByVal progress As Integer) 
    Public Sub DoIt() 
        RaiseEvent OnProgress(…) 
    End Sub 
End Class 
Module Module1 
    Dim WithEvents p As New Processor() 
    Public Sub p_OnProgress(ByVal progress As Integer) _ 
Handles p.OnProgress 
    End Sub 
    Sub Main() 
        p.DoIt() 
    End Sub 
End Module

Ereignisse sind in VB .NET ganz klar ein eigenständiges Konstrukt und Sie müssen sich nicht darum kümmern, wie sie unter der Haube funktionieren. VS .NET unterstützt Sie auch bei der Ereignisbehandlung, in dem es Objektvariablen listet (hier: p), für die Events (hier: OnProgress) definiert sind und auf Wunsch einen Eventhandler generiert (hier: p_OnProgress). Sie können Ihre Aufmerksamkeit also auf die Definition des Event und die Deklaration von Variablen beschränken. So soll es sein.
In C# hingegen ist das selbe Ziel nicht so leicht zu erreichen:

class Processor 
{ 
public delegate void OnProgressDelegate(int progress); 
public event OnProgressDelegate OnProgress; 
public void DoIt() 
{ 
OnProgress(…); 
} 
} 
class Module1 
{ 
public static Processor p = new Processor(); 
static void OnProgressHandler(int progress) 
{ 
} 
static void Main(string[] args) 
{ 
p.OnProgress += new Processor.OnProgressDelegate(OnProgressHandler); 
p.DoIt(); 
} 
}

Der Code ist nicht nur länger und erfordert mehr Tipparbeit, er ist auch viel expliziter. In ihm ist der hinter Ereignissen stehende Mechanismus der delegate-Objekte sichtbar und VS .NET unterstützt Sie nicht bei der Verdrahtung der Ereignisbehandlungsroutine (hier: OnProgressHandler) mit dem ereignisfeuernden Objekt (hier: p).

Warum Microsoft C# in dieser Hinsicht nicht mit mehr Komfort ausgestattet hat, ist mir ein Rätsel. Das reservierte Wort event leistet jedenfalls nicht dasselbe wie in VB .NET. Da Ereignisbehandlung kein "esoterischer" Mechanismus ist, sondern eine grundlegende Programmiertechnik, fällt der Vergleich beider Sprachen also deutlich für VB .NET aus - insbesondere, da der am Ende erzeugte IL-Code fast komplett identisch ist (s. folgende Abbildung).

Bild02

Abbildung 1: Ereignisbehandlungscode im Vergleich: links C#, rechts VB .NET. Bei großen Unterschieden im Programmierkomfort sind die Unterschiede auf IL-Ebene vernachlässigbar.

Weitere Features
Zu den beschriebenen Produktivitätsfeatures von VB .NET kommen weitere, auf die ich hier nicht näher eingehen will. Einige seien noch kurz angerissen:

  • Module in VB .NET werden in Klassen mit ausschließlich statischen Methoden übersetzt. Das bringt zwar keine große Ersparnis im Erfassungsaufwand auch wenn shared vor Deklarationen und Methoden weggelassen werden kann, aber Module unterstreichen den Willen des Entwicklers, Methoden in Form eines API zusammenzufassen. Ihr Code wird damit etwas verständlicher - was nicht heißen soll, dass Sie auf die Vorteile der OOP verzichten sollten, indem Sie vermehrt Module statt Klassen schreiben.

  • Wenn Sie mit .NET Klassen entwickeln wollen, die auch per COM ansprechbar sein sollen, unterstützt VB .NET Sie mit einer COM-Class Klassenvorlage. Sie enthält schon Definitionen von CLSID usw. und sorgt dafür, dass Ihre Klasse nach Übersetzung in der Registry vermerkt wird. Mit C# lässt sich zwar dasselbe erreichen - aber nur mit manuellem Aufwand.

  • Zweischneidig ist sicherlich der Schalter Option Strict On/Off. Er ist standardmäßig ausgestellt und macht VB .NET lax in der Typprüfung zur Übersetzungzeit - was allerdings die Codeeingabe beschleunigt, da Sie weniger explizite Typwandlungen vornehmen müssen. Auf der anderen Seite geben Sie aber natürlich damit Sicherheit auf.

 

Was zu vermissen ist

Bei allen Produktivitätsvorteilen von VB .NET gegenüber C#, lassen sich natürlich auch einige Features vermissen:

  • Die C# using-Anweisung, mit der Ressourcen in Objekten am Ende sozusagen deterministisch freigegeben werden, muss in VB .NET relativ umständlich mit try-finally nachgebildet werden.

  • Der += Operator lässt sich in VB .NET leider nicht auf delegate-Objekte anwenden. Stattdessen müssen Sie AddHandler oder die delegate Combine-Methode verwenden.

  • VB .NET ist Whitespace-sensibel. Sie können z.B. Zuweisungen nicht einfach über mehrere Sourcecodezeilen verteilen, sondern müssen an das Zeilenende das Fortführungszeichen "_" setzen. Das behindert den Schreibfluss ein wenig.

  • Keine Microsoft .NET-Sprache bietet im Augenblick die Möglichkeit eines Run-Debug-Resume. Wie hilfreich und produktivitätsfördernd dieses Feature in VB bisher war, merken Sie wahrscheinlich jetzt erst (wieder), da es (noch) nicht zur Verfügung steht. Es bleibt zu hoffen, dass Microsoft schnellstmöglich nachbessert.

 

Was zu vermeiden ist

Wenn Sie in die Entwicklung mit VB .NET einsteigen und es als Produktivitätswerkzeug im Verein mit anderen sehen, dann müssen Sie auf einige Unterschiede achten, die Ihnen den Wechsel zwischen den Sprachwelten schwer machen können. Zwei seien hier hervorgehoben:

  • Bei der Definition von Feldern verlangt VB .NET (seit Beta 2 wieder) die Angabe der Feldobergrenze. C# und IL hingegen definieren Felder durch Angabe der Feldlänge. Wenn Sie nicht aufpassen, kann es Ihnen also leicht passieren, dass Ihre Felder in VB .NET ein Element zu viel haben. Gewöhnen Sie sich daher vielleicht an, Felder mit Feldlänge-1 zu deklarieren.

  • VB .NET bietet weiterhin eigene Funktionen z.B. für die Zeichenkettenbehandlung. Von Ihrem Gebrauch - so bequem und naheliegend er sein mag - möchte ich jedoch auch zwei Gründen ausdrücklich abraten:

    • 1. Die Zeichenkettenfunktionen sind 1-basiert, alle anderen Feldoperationen jedoch 0-basiert. Ein Wechsel der Indexbasis jedoch führt leicht zu Fehlern beim Umgang mit Feldgrenzen. Sie zu vermeiden ist .NET angetreten, in dem in C# und VB .NET die Felduntergrenze mit 0 festgelegt ist. Mit den Zeichenkettenfunktionen torpedieren Sie also dieses Ziel.

    • 2. VB .NET-eigene Funktionen sind nicht übertragbar in andere Sprachen. Wenn Sie sich auf sie einlassen, haben Sie es schwerer zwischen Sprachwelten zu wechseln, um jede für ihre Vorteile zu nutzen. Und sie machen es anderen Entwicklern schwieriger, Ihren VB .NET-Code zu verstehen. Benutzen Sie daher immer die hinter den VB .NET-Funktionen stehenden Funktionen der .NET Basisklassenbibliothek oder des Common Type System (CTS). Statt z.B. Instr(s, ...) schreiben Sie also besser s.IndexOf(...).

 

Fazit

Während ich Anfang des Jahres 2001 zu Zeiten der .NET Beta 1 noch meine Zweifel hatte, ob VB .NET als Sprache technisch (nicht politisch) wirklich Sinn macht, bin ich davon inzwischen überzeugt. VB .NET lässt mich einfach produktiver sein, wie ich versucht habe, Ihnen anhand einiger Features zu erklären: Ich muss oft weniger Code tippen und die Codeerstellung wird besser durch VS .NET unterstützt als z.B. in C#. (Hinzu kommt, dass auf deutschen Tastaturen das in C# allgegenwärtige Klammerpaar {} nur relativ umständlich über eine Tastenkombination zu erreichen ist.)

VB .NET wird damit natürlich nicht zur per se besten .NET-Sprache. Bei einem solchen Superlativ muss immer gefragt werden, worauf sich ein Vergleich bezieht. In punkto Featurevielfalt, Standardisierung, Akzeptanz steht C# sicherlich noch vor VB .NET; aber diese Kriterien sind nicht immer wichtig. Für viele Bereiche in einem Softwareprojekt ist es unerheblich, ob ich mit vorzeichenlosen Ganzzahlen arbeiten oder Operatoren selbst definieren kann. Da zählt vielmehr die zügige Produktion von Code. Und genau dort, würde ich sagen, liegt die Stärke von VB .NET; das macht den Zweck der Sprache aus. Und wir dürfen gespannt sein, wie Microsoft dies in Zukunft noch mehr betonen wird.