Private this As TSomething

A post on Code Review recently caught my attention (emphasis mine):

If you are setting up a class, don’t encapsulate a Type inside of it – you are only repeating what a class does! I am not sure where this anti-pattern comes from.

The author of these words didn’t use the term “anti-pattern” in the same way I would have… They didn’t mean it as the toxic coding practices I use it for (I know, I asked!). But they aren’t seeing the benefits of it, and ultimately consider it clutter… and that’s where we disagree, regardless of whether “anti-pattern” is incendiary wording or not.

If you’ve been reading this blog for some time, you’ve probably noticed this rather consistent (VBA code written before 2015 doesn’t count!) pattern in my writing of class modules: whenever I need a class, I start by declaring a Private Type for its private instance fields, always named after the class module itself and prefixed with an admittedly rather “Hungarian” T prefix; then the only actual private field in the class is a Private this variable, like this:

Option Explicit
Private Type TPerson
FirstName As String
LastName As String
End Type
Private this As TPerson

Public Property Get FirstName() As String
FirstName = this.FirstName
End Property

Public Property Let FirstName(ByVal value As String)
this.FirstName = value
End Property

Public Property Get LastName() As String
LastName = this.LastName
End Property

Public Property Let LastName(ByVal value As String)
this.LastName = value
End Property

The same class module would “normally” look something like this:

Option Explicit
Private mFirstName As String
Private mLastName As String

Public Property Get FirstName() As String
FirstName = mFirstName
End Property

Public Property Let FirstName(ByVal pFirstName As String)
mFirstName = pFirstName
End Property

Public Property Get LastName() As String
LastName = mLastName
End Property

Public Property Let LastName(ByVal pLastName As String)
mLastName = pLastName
End Property

Yes, it’s less code. So what’s my problem with it?

Several things.

  • Properties and their respective backing field don’t (can’t) use the same identifier.
  • That m prefix is pure clutter that’s only there to say “hey look, this is a private field /module variable!” – in other words, it’s Systems Hungarian notation and does nothing other than increase the cognitive load. Even worse with an underscore, which wrecks the consistent camelCase/PascalCase conventions of literally everything written in any VB dialect.
  • It’s not true that using such Hungarian prefixes helps with autocompletion and IntelliSense. If the class has 5 properties that happen to start with a M, then your 5 backing fields are intertwined with 10 public members (so, drowned, really) that also start with an M.
  • Mutator parameters aren’t consistent either. That p prefix is just as annoying, and I’ll go as far as to say that this m-for-member and p-for-parameter convention is exactly what’s behind the fact that many VBA programmers have never dared implementing a class module “because it’s too confusing” and hard to follow.
  • The locals debugging toolwindow becomes cluttered with all the private fields duplicating the Property Get membersvalues.
mFields-locals
The Locals toolwindow, showing fields and properties as members of Me.

With my “anti-pattern”, there’s a little bit more code, yes. But:

  • Properties and their respective backing field consistently use the same identifier. IntelliSense / autocomplete for my fields consistently only ever includes the backing fields, and all I had to do was to type this..
  • No need for any Hungarian prefix anywhere. I use T for the type declaration (I also use I for interfaces, like in .NET and most C-based languages), because I find that using the class identifier (which would be perfectly legal) would be potentially confusing in Private this As Class1, since in any other context (outside the class module itself) the identifier Class1 in an As clause would be referring to the Class1 class.
  • Parameter names are always explicitly passed ByVal and named value. Yes, this makes Range.Value show up as Range.value, but VBA being case-insensitive, it makes no difference whatsoever. I could have used any other identifier, but value is what VB.NET and C# use; besides RHS isn’t quite as sexy, if more semantically correct. But naming parameters after the property member is an objectively horrible idea; all you see is a soup of mFoo, pFoo and Foo with assignment operators in between.
  • The locals debugging toolwindow now nicely regroups all the fields under this, so the object’s state is much easier to browse and understand at a glance.
  • If you ever need to serialize an object’s state to a binary file, then all you need to do is to Put #fileHandle this and you’re done. The inverse process is just as simple: no need to enumerate the properties one by one, convert them, or manipulate them in any way.
TPerson-locals
The Locals toolwindow, showing properties as members of Me, and a collapsed this member encapsulating the otherwise redundant fields.

I’d love to hear exactly what’s wrong with this “anti-pattern” of mine – I’ve grown pretty fond of it in the past couple years, and until someone can show me how and why I’m actively hurting something somewhere with it, I’ll keep using it in my own code, and posting Code Review and Stack Overflow answers featuring it.. and my blog posts will keep using it too.

One concern raised, was that a UDT doesn’t play well with collections. But this UDT isn’t going to end up in a collection anytime soon – and even if the class instance went into a collection, the encapsulated UDT couldn’t care less: all it does is regrouping the class’ internal state. Code outside the class doesn’t know about it, and couldn’t if it wanted.

You might be worried that a UDT incurs additional overhead… but it doesn’t: it simply provides a convenient structure to organize the private fields of a class. Two Long private fields allocate 4 bytes each and total 8 bytes; a UDT with two Long members allocates a total of 8 bytes, as Len(this) shows. What’s an easy way to know how much space the instance fields of a class take up?

Rubberduck has an encapsulate field refactoring that makes a public field private, renames it, and introduces Property Get and appropriate Property Let/Set mutators for it.

For a while I’ve been considering implementing a feature that builds on this Private Type [anti?] pattern, but held back because I didn’t want Rubberduck to enforce my coding style… although… I would love to be able to just declare my private type and my this private field, parse, and then right-click the UDT field and have Rubberduck generate all the Property Get/Let/Set boilerplate for me.

Would that make it more compelling?

20 thoughts on “Private this As TSomething”

  1. I’ve been using ‘this’ style since I first saw it here on Rubberduck . I think it’s great, it makes the code so much easier to read/write. By just typing ‘this.’ I get a list of all my private fields in IntelliSense.

    I wish I could declare my ‘WithEvents’ variables there as well. 🙂

    Keep up the great work Mat!

    Liked by 2 people

  2. I always wondered what exactly “this” was used for in your example of the self creating classes, thanks to this post I can see the benefits of it now!
    Great work as always!

    Like

  3. I love this pattern!

    1. I agree with Kostas K. and wish there was a way to include WithEvents variables in this approach, but like him I have not found a way to do it. Anyone?

    2. I use the same name, “type_THIS”, for each module’s private type. Since these types are all private, assigning unique names seems unnecessary.

    3. In MZ-Tools 3.0, I use boilerplate “Module Header” code (below). When starting a new module, I delete the two subs that don’t apply, unpack the commented-out code, and add details as needed.

    4. I automatically include “this.ModuleName” as a variable because my error-handling code (omitted) uses it.

    5. Form modules have Open/Close events; class modules have Initialize/Terminate events; but standard modules do not automatically have anything analogous. Therefore, in order to allow reference to “this.ModuleName” in all three module types, in my standard modules “this()” is written a function so that its value is available as soon as it is needed. I do not have a standard-module mechanism analogous to a Close/Terminate event, but since the private types for standard modules will only contain a “ModuleName” string variable, it seems unnecessary.

    ‘ BEGIN MZ-Tools boilerplate “Module Header” code

    Private Sub CodeTemplateForFormModules()

    ‘Private Type type_THIS
    ‘ ModuleName As String
    ‘ Form As Form_{MODULE_NAME}
    ‘End Type

    ‘Private this As type_THIS
    ‘Private blank As type_THIS

    ‘Private Sub Form_Open(ByRef Cancel As Integer)
    ‘ With this
    ‘ .ModuleName = “{MODULE_NAME}”
    ‘ Set .Form = Me
    ‘ End With
    ‘End Sub

    ‘Private Sub Form_Close()
    ‘ this = blank
    ‘End Sub

    End Sub

    Private Sub CodeTemplateForClassModules()

    ” Configure this class to automatically instantiate a global default instance by doing the following:

    ” 1. Manually export this module to a textfile “ThisClassName.cls”
    ” 2. In a text editor, change the “Attribute VB_PredeclaredId” value from “=False” to “=True”
    ” 3. Re-import the textfile into the Visual Basic Editor, save, and re-compile

    ‘Private Type type_THIS
    ‘ ModuleName As String
    ‘ Parameter As Variant
    ‘End Type

    ‘Private this As type_THIS
    ‘Private blank As type_THIS

    ‘Private Sub Class_Initialize()
    ‘ With this
    ‘ .ModuleName = “{MODULE_NAME}”
    ‘ End With
    ‘End Sub

    ‘Private Sub Class_Terminate()
    ‘ this = blank
    ‘End Sub

    ‘Public Function Create(Parameter As Variant) As {MODULE_NAME}
    ‘ With New {MODULE_NAME}
    ‘ .Initialize Parameter
    ‘ Set Create = .Self
    ‘ End With
    ‘End Function

    ‘Public Sub Initialize(Parameter As Variant) As {MODULE_NAME}
    ‘ With this
    ‘ .Parameter = Parameter
    ‘ End With
    ‘End Sub

    ‘Public Property Get Self() As {MODULE_NAME}
    ‘ Set Self = Me
    ‘End Property

    End Sub

    Private Sub CodeTemplateForStandardModules()

    ‘Private Type type_THIS
    ‘ ModuleName As String
    ‘End Type

    ‘Private Function this() As type_THIS
    ‘ With this
    ‘ If .ModuleName = vbNullString Then
    ‘ .ModuleName = “{MODULE_NAME}”
    ‘ End If
    ‘ End With
    ‘End Function

    End Sub

    ‘ END MZ-Tools boilerplate “Module Header” code

    Liked by 1 person

    1. Thanks for the feedback! I would be careful about standard modules though: if your modules need that level of encapsulation then they should probably be classes. As for the MZ boilerplate, that’s a great idea – maybe someone will PR a similar functionality into Rubberduck at one point =)

      Liked by 1 person

  4. Thanks Mathieu! Regarding the standard modules, my only reason for including them in this pattern was to maintain uniformity in the name-of-the-current-module string consumed by my error-handling code. Other than that, I have no encapsulation-related intentions towards them. I am trying to pare down the amount of code I keep in standard modules down to a bare minimum (user-defined types and a couple of public variables).

    Like

    1. Hey Eric, I’ve been thinking about this, and came to the conclusion that the reason I don’t put something like ModuleName in the private type, is because that field is really a Private Const that belongs to the type/class, rather than the object/instance – to take a C# analogy that would be a “static” field (the keyword means something entirely unrelated in VBA though). As such, having it in a standard module (which are essentially “static classes”), doesn’t agree with the idea of the private type holding the internal state of the instance

      Liked by 1 person

      1. Mathieu, I see your point that if the private type is meant to store instance-specific variables then it’s not really an appropriate place in which to store ModuleName (or any other constant values). I have some classes that hold many private constants. It would be nice to be able to organize them in the Object Browser, analogous to how your private type organizes the class’s private variables. If the private constants were all Long values, I could use a private enum for them, but that doesn’t help with constants of other data types. Any ideas?

        Like

      2. Since constants live at module scope, why not declare them in their own dedicated module, and use them fully-qualified? e.g. class ‘Foo’ could use ‘FooConstants.Bar’? Similar to how type libraries do with their ‘Constants’ module, just more granular. I think that’s what I would go with. It does make them all public/global though.

        Like

  5. Mathieu, I see your point that if the private type is meant to store instance-specific variables then it’s not really an appropriate place in which to store ModuleName (or any other constant values). I have some classes that hold many private constants. It would be nice to be able to organize them in the Object Browser, analogous to how your private type organizes the class’s private variables. If the private constants were all Long values, I could use a private enum for them, but that doesn’t help with constants of other data types. Any ideas?

    Like

  6. I started using this pattern a few years ago. I believe I saw it on one of your posts, probably on Code Review. I just wanted to second Eric Sadoyama’s note about giving the Type the same name in every class. I use a different name than Eric does, but echo his thinking on the topic.

    I have not come across any problems with this approach and I actually think it improves readability of the code. I hadn’t considered the application in serializing and deserializing the classes to/from text files. That is an interesting solution. Now I just have to find a suitable problem for it to solve. 🙂

    Liked by 1 person

  7. I’m really learning from all of your posts. I will also implement this coding style. Actually, since rubberduck is “not yet” implementing this, I created a shortcut insert using MZ-Tools. 🙂

    Liked by 1 person

  8. As usual, amazing explanation and I can see the advantages. As a user of MZTools and CodeVBA, I really get tired of the “need of hungarian” prefix over all private variables; many, many thanks. And the Intellisense that it provides pays any extra typing… it has to become official!
    Deepening the discussion, I sense that is better to use the private variables to access the fields inside the class itself, but after seeing this discussion (https://stackoverflow.com/questions/40995620/is-it-better-to-use-getters-or-to-access-private-members-directly), I really am divided…
    What do you, gentlepeople, think? What should be the “VBAonic” way?

    Liked by 1 person

    1. Thanks!
      I think that SO discussion went a bit astray: if a field needs additional logic, in my mind that logic belongs on the setter, and the getter is always as stupid-simple as it can be (getters should never throw errors, no matter what… except indexers/parameterized getters, which may throw an index out of range error) – if other code assigns to a property, then that setter needs to implement the validation logic and throw an error if the value can’t be assigned (in VBA that would be error 5 “invalid argument”) – that way the getter and its backing field always have the same value and all the getter does is forward the encapsulated value to the caller… and then it makes no sense to access a private field from a public getter when you’re inside that class: it’s just a level of indirection that the class itself doesn’t need to have; it makes the reader question whether the getter is doing anything special, …and waste their time noticing it doesn’t.

      Bottom line, using a class’ public interface in private implementation details, creates more confusion than needed IMO. Transposing to VBA, that means I’d write this.Something over Me.Something unless there’s a good/valid reason to go through the public API.

      Liked by 1 person

  9. Clear as crystal – not the reports 😉
    I’m refactoring tons of my own legacy code… I was lost, but with the help of M. Feathers’s Working Effectively with Legacy Code and your’s blog and RubberDuck tool I’m making progress, and even having fun on the way.
    Thanks again
    PS: I’m the same Marcelo at Aug 29 as above; could not log in with the same ID…

    Liked by 1 person

  10. I’m a student learning C++ currently, and I was curious: Does this pattern translate as good practice to any other languages such as C++? Like for example: Using a C++ struct within a class instead of a VBA user defined type.

    Like

    1. Good question! I don’t think it translates very well, it’s more of a work-around to help IntelliSense a bit and clean up a crowded Locals toolwindow; I would definitely stick to standards in C++ (disclaimer: I don’t write much C++). In C# and several other languages, “this” already exists, and identifiers get to legally start with an underscore to it’s easy to avoid needing the explicit qualifier if you want to, not to mention case-insensitivity so “thing” can easily be the backing private field for a “Thing” property.

      Like

Leave a comment