OK, quick quiz. And, yes, this is a trick question. Without looking at VS, what do you expect the following code to print?
Public Sub Foo()
Dim s1, s2 As String
s1 = "abc"
Yes, that’s right, it prints nothing. Wha….? Because
String.Copy is a shared function that takes a string and returns a copy of it. It has no effect on the instance that it’s being called on.
Another quick quiz. And, yes, this is also a trick question. Without looking at VS, what do you expect the following code to print?
Public Class Foo
Public Shared Baz As Integer = 10
Public Function Bar() As Foo
Return New Foo()
Dim y As Integer
y = Bar().Baz
Yes, that’s right, it prints nothing. Wha….? Since
Baz is a shared member, we do not need to evaluate the qualifying instance expression, so we don’t. So
Bar is never called.
In general, it is a bad idea to call shared members off of instance expressions for these two reasons. Shared members cannot affect instances directly, so calling shared methods or changing shared properties/fields off of an instance may give surprising results. And because we do not evaluate expressions that qualify shared members, you won’t get side effects where you might expect it. (This has bitten even a few members of the VB team themselves.)
A legitimate question then is, if it’s a bad idea, why do we allow it in the first place? Unfortunately, the original logic has been lost to history – my grey matter no longer contains the memory of when and why we decided to allow this. One possible reason is that disallowing shared member access off of an instance expression causes problems in a common situation:
Public Color As Color = Color.Red
With just the simple rule that shared members cannot be accessed off of instances, the field declaration in Control would be in error. This is because the
Color.Red will bind first to the field
Control.Color, which is an instance field. Which means you can’t access shared members off of it, and enum members are shared. C# fixes this problem by introducing a special rule: in a context where the name of a variable is the same as the name of its type, you can access shared instances off of an instance. As it turns out, we had to introduce this rule anyway late in VS 2002 for the following related situation:
Public Color As Color
Public Shared Sub Bar(ByVal SomeControl As Control)
SomeControl.Color = Color.Red
In this case, the
Color.Red still binds to the instance field, but you run afoul of the rule that says that you can’t access instance members in a shared context.
Whatever the original logic, it’s become clear that this is not a good design and that we made a mistake in allowing it. (Yes, Virginia, we do make occasionally make mistakes around here.) I encourage people to avoid using it whenever possible. Unfortunately, the compiler doesn’t really help you on this today, but it’s something we’re be helping you more with in the future.