Visual Basic for Programmers of Other Languages
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The reference material consulted while preparing these pages is listed in the section bibliography. |
This page was checked on 2026-10-19 against Visual Basic 17.13 on .NET 10 (LTS, SDK 10.0.402); .NET 11 was a release candidate that day and is treated as upcoming. It is written for someone who already programs in another language and wants to read and write Visual Basic without being surprised. Every program on it was built with Option Strict On and warnings as errors and run in the official mcr.microsoft.com/dotnet/sdk:10.0 container image, and the output shown is the real output. The page starts with the dozen rules that cause most of the surprises, each shown by a program, then gives side-by-side maps to C#, Java and VB6/VBA, a flowchart that answers "which Visual Basic feature replaces …", and a list of the usual mistakes. The language is explained in order starting from Program Structure and Code Conventions; the platform it runs on is the same as C#'s, see Visual Basic and .NET.
Visual Basic and C# compile to the same intermediate language for the same runtime, and they share the .NET libraries, so most of what matters about the platform (collections, LINQ, async, IDisposable, generics) is identical. The differences are in the syntax, in a few semantic defaults inherited from older BASIC dialects, and in a handful of features that only Visual Basic has. The C# reference is at C# and .NET and the Java reference starts at Java Getting Started.
The surprises at a glance
| Surprise | Rule | Page |
|---|---|---|
Names ignore case |
|
|
Statements end at the end of the line |
There are no semicolons. A statement continues on the next line after an operator, a comma or an opening bracket (implicit continuation since Visual Basic 10), or after an explicit |
|
|
The compiler allows implicit narrowing and late binding unless |
|
Array declarations give the upper bound |
|
|
|
The meaning depends on the position: a statement that starts with a target assigns; inside an expression it compares. There is no |
|
|
|
|
|
|
|
|
Use |
|
|
Both operands are always evaluated. |
|
|
For a reference type it is the null reference; for a value type it is the default (0, |
|
|
|
|
Arithmetic overflow throws |
Integer arithmetic is checked by default (the C# default is unchecked). |
|
|
Features that only Visual Basic has: a type with only shared members and no |
see the sections below |
Names, lines and defaults
Names ignore case
The compiler treats identifiers case-insensitively, as BASIC always did. A variable declared as copies can be used as COPIES, and console.writeline is Console.WriteLine. In Visual Studio the editor rewrites each use to the case of the declaration, so in practice you rarely type the variants by accident, and the habit of naming a field Title and a parameter title that C# programmers rely on still works, because the two live in different scopes and Me.Title disambiguates them. What does not work is a same-scope pair that differs only in case.
Option Strict On
Module Program
Sub Main()
Dim line As String = "Reference"
Dim Line As Integer = 3
Console.WriteLine(line)
End Sub
End Module
Program.vb(7,13): error BC30288: Local variable 'Line' is already declared in the current block.
Case-insensitivity has a consequence for type names too. A local variable named host is refused when the same method also uses the type Host (BC32000: Local variable 'host' cannot be referred to before it is declared), as met on Visual Basic and .NET. The usual cure is the same as in any language: a different name. Naming conventions for Visual Basic (PascalCase for types and members, camelCase for locals and parameters, no Hungarian prefixes) are on XML Documentation, Analyzers and Code Style.
Several surprises in one program
The next program shows case-insensitive names, upper-bound array declarations, = as assignment and comparison, Nothing as a default, and the meaning of one As clause for several names.
Option Strict On
Module Program
Structure Point2D
Public X As Integer
Public Y As Integer
End Structure
Sub Main()
Console.WriteLine("-- names ignore case")
Dim copies As Integer = 3
COPIES += 1
Console.WriteLine(Copies)
console.writeline("still Console.WriteLine")
Console.WriteLine("-- array declarations give the upper bound")
Dim shelf(3) As String
Console.WriteLine(shelf.Length & " " & shelf.GetUpperBound(0) & " " & UBound(shelf))
Dim grid(2, 4) As Integer
Console.WriteLine(grid.GetLength(0) & " x " & grid.GetLength(1))
Dim shelfSlots = New String(3) {}
Console.WriteLine(shelfSlots.Length)
Console.WriteLine("-- = assigns in a statement and compares in an expression")
Dim a As Integer = 5
Dim b As Boolean = a = 5
Dim c As Boolean = (a = 6)
Console.WriteLine(b & " " & c)
Console.WriteLine("-- Nothing is the default value of any type")
Dim count As Integer = Nothing
Dim flag As Boolean = Nothing
Dim title As String = Nothing
Dim origin As Point2D = Nothing
Console.WriteLine(count & " " & flag & " [" & title & "] " & origin.X & "," & origin.Y)
Dim empty As String = ""
Console.WriteLine((empty = Nothing) & " " & (empty Is Nothing) & " " & String.IsNullOrEmpty(empty))
Console.WriteLine("-- one As clause types every name in the list")
Dim low, high As Integer
Console.WriteLine(low.GetType().Name & " " & high.GetType().Name)
End Sub
End Module
-- names ignore case
4
still Console.WriteLine
-- array declarations give the upper bound
4 3 3
3 x 5
4
-- = assigns in a statement and compares in an expression
True False
-- Nothing is the default value of any type
0 False [] 0,0
True False True
-- one As clause types every name in the list
Int32 Int32
Source: Arrays in Visual Basic, Nothing
Points to take from the output:
-
Dim shelf(3) As Stringholds 4 elements:Lengthis 4 and the upper bound is 3. The number is the upper bound, the opposite of a C# or Javanew string[3].Dim grid(2, 4)is a 3 by 5 array. The initializer formNew String(3) {}follows the same rule. Because the declaration is an upper bound, a loop is writtenFor i = 0 To shelf.Length - 1orFor i = 0 To UBound(shelf), and an off-by-one is a classic mistake in code ported from other languages (see Arrays). -
The statement
COPIES += 1is an assignment; the same=inDim b As Boolean = a = 5first comparesawith 5 and then assigns the result tob. There is no way to assign inside an expression, so the C# idiomwhile line = reader.ReadLine( != null)has no direct form; Visual Basic reads the line first and tests it, or usesDo ... Loop Until. -
Nothingassigned to anInteger, aBooleanor a structure gives the default value, not a null reference. The last line of that block is a classic trap: comparing an empty string withNothingusing=givesTrue, because the string comparison treats a null string and an empty string as equal, while the reference testIs NothingsaysFalse. UseString.IsNullOrEmptywhen you mean either. -
In
Dim low, high As Integerboth names areInteger, unlike VB6 where only the last one was typed.
Lines, continuation and comments
A statement ends at the end of the physical line. A long expression can be broken after an operator, a comma, an opening bracket or brace, a ., and several keywords without any marker (implicit line continuation, Visual Basic 10); anywhere else a trailing underscore continues the line, and since Visual Basic 16 a comment is allowed after it. Comments start with an apostrophe and run to the end of the line (Rem is an old alternative); there is no block comment. ''' starts an XML documentation comment. A colon separates statements on one line, which the examples of this reference avoid except for a very short pair. A single-line If ... Then ... Else ... needs no End If; a block If does, and its ElseIf is one word. The line-oriented grammar also means that braces appear only in array and collection initializers ({10, 20, 30}) and in object initializers (With {.Name = "Reference"}), never around blocks.
Another handful of small differences
Option Strict On
Module Program
Sub Main()
Dim copies As Integer? = Nothing
Console.WriteLine("[" & (copies = 1).ToString() & "]")
If copies = 1 Then
Console.WriteLine("equal")
ElseIf copies <> 1 Then
Console.WriteLine("different")
Else
Console.WriteLine("neither: a comparison with Nothing is Nothing, not False")
End If
Console.WriteLine(copies.HasValue & " " & copies.GetValueOrDefault())
Dim text As String = "a" & vbTab & "b"
Console.WriteLine(text.Length)
Dim quote As String = "She said ""hi"""
Console.WriteLine(quote)
Dim letter As Char = "x"c
Console.WriteLine(letter)
Dim items As Integer() = {10, 20, 30}
Console.WriteLine(items(1))
Dim w As Long = 5L : Dim r As Double = 1.5R : Dim m As Decimal = 2.5D : Dim s As Single = 1.5F
Console.WriteLine(w & " " & r & " " & m & " " & s)
End Sub
End Module
[]
neither: a comparison with Nothing is Nothing, not False
False 0
3
She said "hi"
x
20
5 1.5 2.5 1.5
Source: Nullable value types, Type characters
Five more points from it. A comparison with a nullable value that holds Nothing is itself Nothing (a null Boolean?), and an If treats it as false, so both copies = 1 and copies <> 1 were false above and the Else ran: this three-valued logic is different from C#, where == on a null nullable gives false and != gives true. String literals have no backslash escapes: a double quote is doubled (""), and the control characters are the constants vbTab, vbCrLf, vbNewLine or Environment.NewLine. A one-character Char literal carries the suffix c ("x"c), because "x" is a string. Indexing an array or calling a method both use parentheses, so items(1) is the second element, and the same brackets are used for generic type arguments with the keyword Of (List(Of String)). Literal suffixes are letters (L, UI, F, R, D) rather than C#'s L, u, f, d, m.
Numbers and operators
Option Strict On
Module Program
Function Loud(label As String, value As Boolean) As Boolean
Console.WriteLine(" evaluated " & label)
Return value
End Function
Sub Main()
Console.WriteLine("-- division")
Console.WriteLine(7 / 2) ' Double
Console.WriteLine(7 \ 2) ' integer division
Console.WriteLine(7 Mod 2)
Console.WriteLine(-7 \ 2) ' truncates toward zero
Console.WriteLine((7 / 2).GetType().Name & " " & (7 \ 2).GetType().Name)
Console.WriteLine("-- power is always Double")
Console.WriteLine((2 ^ 3).GetType().Name & " " & (2 ^ 3))
Dim cube As Integer = CInt(2 ^ 3)
Console.WriteLine(cube)
Console.WriteLine("-- & concatenates, + adds when both are numbers")
Console.WriteLine("Copies: " & 3 & 4)
Console.WriteLine(3 + 4)
Console.WriteLine("-- And / Or do not short-circuit")
Dim ignored1 As Boolean = Loud("left", False) And Loud("right", True)
Dim ignored2 As Boolean = Loud("left", False) AndAlso Loud("right", True)
Console.WriteLine(ignored1 = ignored2)
Console.WriteLine("-- True is -1 when converted to a number")
Console.WriteLine(CInt(True) & " " & CInt(False) & " " & CStr(True) & " " & Convert.ToInt32(True))
Console.WriteLine("-- integer overflow is checked by default")
Dim big As Integer = Integer.MaxValue
Try
big += 1
Catch ex As OverflowException
Console.WriteLine(ex.GetType().Name & ": " & ex.Message)
End Try
End Sub
End Module
-- division
3.5
3
1
-3
Double Int32
-- power is always Double
Double 8
8
-- & concatenates, + adds when both are numbers
Copies: 34
7
-- And / Or do not short-circuit
evaluated left
evaluated right
evaluated left
True
-- True is -1 when converted to a number
-1 0 True 1
-- integer overflow is checked by default
OverflowException: Arithmetic operation resulted in an overflow.
What each block teaches:
-
Division.
7 / 2is theDouble3.5 even for two integers, so dividing integers never loses the fraction by accident;7 \ 2is the integer 3 and-7 \ 2is -3 (it truncates toward zero). Dividing by a zero variable with\orModthrowsDivideByZeroException, while7 / zeroprintsInfinityand throws nothing, because it is floating-point; a literal zero (7 \ 0) is refused at compile time (BC30542, division by zero occurred while evaluating this expression). See Numbers and Math. -
Power.
2 ^ 3is aDouble; to get an integer, convert (CInt(2 ^ 3)).^binds tighter than the unary minus on its left (-2 ^ 2is -4, checked), and the operator is left-associative, so2 ^ 3 ^ 2is 64, not 512 (checked). The precedence ladder is on Operators and Expressions. -
Strings.
"Copies: " & 3 & 4isCopies: 34:&always converts both sides to strings.3 + 4is 7. Mixing a string and a number with+is allowed only whenOption Strictis off, where the compiler tries to convert the text to a number and can fail at run time; withOption Strict On"Total: " + 3does not compile (BC30512, no implicit conversion from 'String' to 'Double'). -
Logic. The output shows
Andevaluatingrightalthoughleftwas alreadyFalse;AndAlsostopped after the left operand. In conditions that guard againstNothing(If x IsNot Nothing AndAlso x.Length > 0) only the short-circuit forms are correct. On integers,And,Or,XorandNotare bitwise; the same word is the logical operator when both operands are Boolean. -
Booleans.
CInt(True)is -1 (all bits set, the VB6 convention kept for compatibility) whileConvert.ToInt32(True)is 1. Do not use the numeric value of a Boolean for anything. -
Overflow. Adding 1 to an
Integervariable that holdsInteger.MaxValuethrowsOverflowExceptionin Visual Basic (a constant expression such asInteger.MaxValue + 1is refused at compile time instead). C# wraps around silently unlesscheckedis used. The project propertyRemoveIntegerChecksturns checking off (see Projects, MSBuild and the dotnet CLI).
Bitwise and comparison operators next to C#
Option Strict On
Module Program
Sub Main()
Dim flags As Integer = 5 ' binary 101
Console.WriteLine(flags And 3) ' bitwise on integers (C# &)
Console.WriteLine(flags Or 2) ' (C# |)
Console.WriteLine(flags Xor 1) ' (C# ^)
Console.WriteLine(Not flags) ' bitwise complement (C# ~)
Console.WriteLine(flags << 2) ' shifts exist since VB 7.1
Console.WriteLine((flags And 1) = 1) ' parentheses: = binds tighter than And
Console.WriteLine("shelf" = "SHELF") ' Option Compare Binary: case-sensitive
Console.WriteLine("shelf" <> "Shelf") ' <> is inequality (C# !=)
Dim a As Object = "x"
Dim b As Object = a
Console.WriteLine((a Is b) & " " & (a IsNot Nothing)) ' reference equality: Is / IsNot
Console.WriteLine(-7 Mod 3) ' remainder keeps the sign of the dividend
Console.WriteLine(Math.Pow(2, 10)) ' same as 2 ^ 10
End Sub
End Module
1
7
4
-6
20
True
False
True
True True
-1
1024
In flags And 1 = 1 the comparison binds tighter than And, so without the parentheses the compiler reads flags And (1 = 1) and refuses it under Option Strict On (BC30512: it cannot convert a Boolean to an Integer); the parentheses are the fix. String comparison with = is case-sensitive under the default Option Compare Binary; Option Compare Text makes it case-insensitive for the whole file.
Visual Basic’s own constructs
Modules, shared members and the missing static
C# has static class; Java has static members; Visual Basic has the Module. Every member of a module is implicitly shared, nobody can create an instance of it, and its members can be called without the module’s name from anywhere in the same namespace, which makes a module the natural home for helper functions and for Sub Main. Shared marks a static member of an ordinary class, and Static (a different word) declares a local variable that keeps its value between calls. The program below puts the common C# and Java constructs next to their Visual Basic form; every comment names the construct it replaces.
Option Strict On
Imports System.IO
' abstract class -> MustInherit virtual / override -> Overridable / Overrides
Public MustInherit Class CatalogItem
Public Property Title As String
Public Shared Count As Integer ' static field -> Shared
Protected Sub New(title As String)
Me.Title = title ' this -> Me
Count += 1
End Sub
Public MustOverride ReadOnly Property Kind As String
Public Overridable Function Describe() As String
Return Kind & ": " & Title
End Function
End Class
Public Class Book
Inherits CatalogItem ' class Book : CatalogItem
Public Sub New(title As String)
MyBase.New(title) ' base(title) -> MyBase.New
End Sub
Public Overrides ReadOnly Property Kind As String
Get
Return "Book"
End Get
End Property
End Class
Public NotInheritable Class Magazine ' sealed -> NotInheritable
Inherits CatalogItem
Friend ReadOnly Issue As Integer ' internal readonly -> Friend ReadOnly
Public Sub New(title As String, issue As Integer)
MyBase.New(title)
Me.Issue = issue
End Sub
Public Overrides ReadOnly Property Kind As String
Get
Return "Magazine"
End Get
End Property
Public Overrides Function Describe() As String
Return MyBase.Describe() & " #" & Issue
End Function
End Class
' static class -> Module: every member is shared, no instance can be created
Module Toolbox
Private ReadOnly Gate As New Object()
Iterator Function Countdown(start As Integer) As IEnumerable(Of Integer) ' yield return -> Yield
For i As Integer = start To 1 Step -1
Yield i
Next
End Function
Function Grade(copies As Integer) As String ' switch -> Select Case
Select Case copies
Case 0
Return "none"
Case 1 To 3
Return "few"
Case Is > 3
Return "many"
Case Else
Return "invalid"
End Select
End Function
Function Visits() As Integer
Static calls As Integer ' static local -> Static
SyncLock Gate ' lock (gate) -> SyncLock
calls += 1
End SyncLock
Return calls
End Function
Function Sum(ParamArray values As Integer()) As Integer ' params -> ParamArray
Return values.Sum()
End Function
Sub Swap(ByRef a As Integer, ByRef b As Integer) ' ref / out -> ByRef
Dim t As Integer = a
a = b
b = t
End Sub
End Module
Module Program
Sub Main()
Dim items As New List(Of CatalogItem) From {New Book("Atlas"), New Magazine("Nature", 7)}
For Each item As CatalogItem In items ' foreach -> For Each
Dim asMagazine As Magazine = TryCast(item, Magazine) ' as -> TryCast
Console.WriteLine(item.Describe() & If(TypeOf item Is Book, " (book)", "") &
If(asMagazine IsNot Nothing, " issue " & asMagazine.Issue, ""))
Next
Dim nickname As String = Nothing
Console.WriteLine(If(nickname, "anonymous")) ' ?? -> If(a, b)
Console.WriteLine(If(CatalogItem.Count > 1, "many", "one")) ' ?: -> If(c, a, b)
Console.WriteLine(Toolbox.Grade(2) & " " & Toolbox.Grade(9) & " " & Toolbox.Grade(-1))
Console.WriteLine(String.Join(",", Toolbox.Countdown(3)))
Console.WriteLine(Toolbox.Visits() & Toolbox.Visits())
Console.WriteLine(Toolbox.Sum(1, 2, 3))
Dim x As Integer = 1, y As Integer = 2
Toolbox.Swap(x, y)
Console.WriteLine(x & " " & y)
Dim titles = From item In items ' LINQ query syntax
Where item.Title.Length > 5
Select item.Title.ToUpperInvariant()
Console.WriteLine(String.Join(";", titles))
Dim twice As Func(Of Integer, Integer) = Function(n) n * 2 ' (n) => n * 2
Console.WriteLine(twice(21))
Using writer As New StringWriter() ' using (var w = ...) { }
writer.Write("disposed at End Using")
Console.WriteLine(writer.ToString())
End Using
End Sub
End Module
Book: Atlas (book)
Magazine: Nature #7 issue 7
anonymous
many
few many invalid
3,2,1
12
6
2 1
NATURE
42
disposed at End Using
Things worth noticing in that program. Module Toolbox has a Private ReadOnly Gate field and no Shared keyword anywhere: inside a module everything is shared. Visits() printed 12 for two calls because the Static local calls survives between calls (the two numbers are printed one after the other without a separator because & joins them). Select Case never falls through: each Case ends the statement, so there is no break; a Case can list values (Case 1, 3, 5), a range (1 To 3) or a comparison (Is > 3). TypeOf item Is Book is the type test, TryCast is the as operator (it returns Nothing when the cast fails), and DirectCast and CType are the casts that throw. A method that returns a value uses Return; the older habit of assigning to the function’s name still compiles and is covered on Procedures: Sub and Function. The module pattern, Shared members and the Static statement are on Modules and Shared Members.
Events: Handles and WithEvents
C# attaches a handler with +=. Visual Basic offers that too (AddHandler) and a declarative form: a field declared WithEvents can have methods that say which of its events they handle, with a Handles clause. Windows Forms code generated by the designer uses the second form for every control. The program shows both.
Option Strict On
Public Class Loan
Public Event Returned As EventHandler ' public event EventHandler Returned;
Public Sub [Return]()
RaiseEvent Returned(Me, EventArgs.Empty) ' Returned?.Invoke(this, EventArgs.Empty)
End Sub
End Class
Public Class Desk
Private WithEvents _loan As New Loan() ' a field that raises events, handled by name
Private Sub OnReturned(sender As Object, e As EventArgs) Handles _loan.Returned
Console.WriteLine("Handles clause: loan returned")
End Sub
Public Sub Run()
Dim extra As EventHandler = Sub(s, e) Console.WriteLine("AddHandler lambda: loan returned")
AddHandler _loan.Returned, extra ' _loan.Returned += extra
_loan.Return()
RemoveHandler _loan.Returned, extra ' _loan.Returned -= extra
_loan.Return()
End Sub
End Class
Module Program
Sub Main()
Call New Desk().Run()
Dim title As String = "Atlas"
Dim book As XElement = <book year="1999">
<title><%= title %></title>
<author>Ada</author>
</book>
Console.WriteLine(book.@year & " " & book.<title>.Value)
Console.WriteLine(book)
End Sub
End Module
Handles clause: loan returned
AddHandler lambda: loan returned
Handles clause: loan returned
1999 Atlas
<book year="1999">
<title>Atlas</title>
<author>Ada</author>
</book>
Four details. The event is raised with RaiseEvent, which does the null check that C# writes as ?.Invoke. A method that is named Return must be written in square brackets ([Return]), because Return is a keyword; the brackets let any keyword be used as an identifier. The statement Public Event Returned(sender As Object, e As EventArgs) is also legal, but declares a new delegate type (Loan.ReturnedEventHandler) instead of using EventHandler; assigning an EventHandler to such an event is then error BC30311 (the value cannot be converted), which is why the example declares Public Event Returned As EventHandler. Finally, the XML element is a literal: it is a XElement created by the compiler, with the embedded expression <%= title %>, the attribute accessed as book.@year and the child elements as book.<title>. XML literals and the axis properties exist only in Visual Basic and are covered on XML Literals and Axis Properties; events are covered on Events and Handlers.
My and default instances
My is a Visual Basic-only namespace of shortcuts to the application, the computer, the user, resources and settings. On .NET Framework it exists in every project; on .NET it is present only in Windows desktop projects whose MyType is set, and is empty in a console project (see The My Namespace for the details and the alternatives). A related feature of Windows Forms projects, the default instance, lets code call Form1.Show() on the class name as if it were a variable; it exists to ease VB6 migrations and is covered on Windows Forms Applications.
Side-by-side maps
To C# and Java
| Concept | Visual Basic | C# | Java |
|---|---|---|---|
Import and namespace |
|
|
|
Inheritance and interfaces |
|
|
|
Abstract, sealed |
|
|
|
Virtual and override |
|
|
methods are virtual; |
Static and module |
|
|
|
Visibility |
|
|
|
Constants and read-only |
|
|
|
This and base |
|
|
|
Null and the null test |
|
|
|
Type test and casts |
|
|
|
Conditional and coalescing |
|
|
|
Logical operators |
|
|
|
Equality |
|
|
|
Loops and switch |
|
|
|
Exceptions |
|
|
|
Disposal and locking |
|
|
try-with-resources, |
Generics |
|
|
|
Lambdas and delegates |
|
|
|
Properties |
|
|
getters and setters |
Parameters |
|
by value (default), |
by value only, overloads, varargs |
Strings |
|
|
|
Comments |
|
|
|
Type of an expression |
|
|
|
The C# page of this reference for the matching topics: Control Flow in C#, Classes and Objects in C# and LINQ in C#; for Java: Java Classes and Objects, Java Inheritance and Polymorphism and Java Exceptions. What does not have a counterpart: Visual Basic has no pattern-matching switch, no record, no required members, no primary constructors and no top-level statements, and C# has no XML literals, Handles, WithEvents, My, Select Case ... Case Is or non-short-circuit boolean operators.
To VB6 and VBA
Visual Basic .NET is not VB6 with a new runtime; it kept the surface and changed the semantics. The legacy dialects are covered on The VB Family: VB6, VBA and VBScript, and the migration path on Migrating Legacy Visual Basic. The shortest map from VB6 and VBA to the current language:
| VB6 or VBA | Visual Basic on .NET 10 |
|---|---|
|
|
|
|
|
|
|
|
|
Plain assignment; |
|
|
|
|
|
Always zero-based. |
|
|
|
|
|
|
|
Removed. Declare every variable. |
|
Both are |
Source: Visual Basic: Getting started
Which Visual Basic feature replaces …?
The flowchart answers the question programmers ask most often when they move to Visual Basic: this construct in my language, what is the Visual Basic way? It covers the replacements that need a different keyword or a different pattern, not the ones that are the same word with another case.
Source: Visual Basic language reference
Where the books are outdated for this page
The two books that this section draws on compare Visual Basic with its older dialects, and some of what they say about those comparisons is out of date or incorrect. The corrected rules, in short:
-
Visual Basic .NET is not source-compatible with VB6. The books' remark that "backward compatibility" eases the transition applies to habits, not to code, and there are many semantic differences (type sizes, default parameter passing, the object model, the library).
-
Of the keywords above, the ones the books describe as VB6 features that the language lacks, or gained, should be checked against the lists on The VB Family: VB6, VBA and VBScript: VB6 had
Implementsbut no class inheritance, VB6 did havePublic,PrivateandFriend, and VBScript 5.0 and later hasClass ... End Class. -
The books present
Option Strict Offcode and the+operator for strings as normal. Neither is recommended: setOption Strict Onand use&. -
They describe Visual Basic as a language that is still gaining features and a runtime that is part of the .NET Framework; see History, Versions and Language Strategy.
Common mistakes for newcomers
| Mistake | What happens, and the fix |
|---|---|
|
It has four. Use |
|
Parsed as |
|
Both operands are evaluated, so a null |
|
|
|
Not text concatenation; with |
|
|
Adding 1 to a variable holding |
|
A nullable |
With |
A local and a type with the same name in different case ( |
Names are case-insensitive. Rename the local. |
|
The event has its own delegate type. Declare |
Calling |
|
Using a keyword as a name ( |
BC30183, keyword not valid as an identifier. Use another name or put the identifier in brackets. |