[vb.net] Classes vs. Modules in VB.NET

Is it considered an acceptable practice to use Modules instead of Classes with Shared member functions in VB.NET?

I tend to avoid Modules, because they feel like leftover remains from Visual Basic 6.0 and don't really seem to fit in anymore. On the other hand, there doesn't seem to be much difference between using a Module and a Class with only Shared members. It's not that often that I really have much need for either, but sometimes there are situations where they present a simple solution.

I'm curious to hear whether you have any opinion or preferences one way or the other.

This question is related to vb.net

The answer is


It is acceptable to use Module. Module is not used as a replacement for Class. Module serves its own purpose. The purpose of Module is to use as a container for

  • extension methods,
  • variables that are not specific to any Class, or
  • variables that do not fit properly in any Class.

Module is not like a Class since you cannot

  • inherit from a Module,
  • implement an Interface with a Module,
  • nor create an instance of a Module.

Anything inside a Module can be directly accessed within the Module assembly without referring to the Module by its name. By default, the access level for a Module is Friend.


Classes

  • classes can be instantiated as objects
  • Object data exists separately for each instantiated object.
  • classes can implement interfaces.
  • Members defined within a class are scoped within a specific instance of the class and exist only for the lifetime of the object.
  • To access class members from outside a class, you must use fully qualified names in the format of Object.Member.

Modules

  • Modules cannot be instantiated as objects,Because there is only one copy of a standard module's data, when one part of your program changes a public variable in a standard module, it will be visible to the entire program.
  • Members declared within a module are publicly accessible by default.
  • It can be accessed by any code that can access the module.
  • This means that variables in a standard module are effectively global variables because they are visible from anywhere in your project, and they exist for the life of the program.

Modules are fine for storing enums and some global variables, constants and shared functions. its very good thing and I often use it. Declared variables are visible acros entire project.


I think it's a good idea to keep avoiding modules unless you stick them into separate namespaces. Because in Intellisense methods in modules will be visible from everywhere in that namespace.

So instead of ModuleName.MyMethod() you end up with MyMethod() popups in anywhere and this kind of invalidates the encapsulation. (at least in the programming level).

That's why I always try to create Class with shared methods, seems so much better.


When one of my VB.NET classes has all shared members I either convert it to a Module with a matching (or otherwise appropriate) namespace or I make the class not inheritable and not constructable:

Public NotInheritable Class MyClass1

   Private Sub New()
      'Contains only shared members.
      'Private constructor means the class cannot be instantiated.
   End Sub

End Class

Modules are by no means deprecated and are used heavily in the VB language. It's the only way for instance to implement an extension method in VB.Net.

There is one huge difference between Modules and Classes with Static Members. Any method defined on a Module is globally accessible as long as the Module is available in the current namespace. In effect a Module allows you to define global methods. This is something that a class with only shared members cannot do.

Here's a quick example that I use a lot when writing VB code that interops with raw COM interfaces.

Module Interop
  Public Function Succeeded(ByVal hr as Integer) As Boolean
    ...
  End Function

  Public Function Failed(ByVal hr As Integer) As Boolean
    ...
  End Function
End Module

Class SomeClass
  Sub Foo()
    Dim hr = CallSomeHrMethod()
    if Succeeded(hr) then
      ..
    End If
  End Sub
End Class

You must use a Module (rather than a Class) if you're creating Extension methods. In VB.NET I'm not aware of another option.

Being resistant to Modules myself, I just spent a worthless couple of hours trying to work out how to add some boilerplate code to resolve embedded assemblies in one, only to find out that Sub New() (Module) and Shared Sub New() (Class) are equivalent. (I didn't even know there was a callable Sub New() in a Module!)

So I just threw the EmbeddedAssembly.Load and AddHandler AppDomain.CurrentDomain.AssemblyResolve lines in there and Bob became my uncle.

Addendum: I haven't checked it out 100% yet, but I have an inkling that Sub New() runs in a different order in a Module than a Class, just going by the fact that I had to move some declarations to inside methods from outside to avoid errors.