🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

VBA Property in Excel — Get, Let and Set (Controlled Access to a Class's Fields)

|

VBA Property in Excel — Get, Let and Set (Controlled Access to a Class's Fields)

TL;DR — A Property turns a field of a class into a gate. From the caller's side emp.Salary = 65000 looks like a plain variable, but behind that assignment your code runs — so you can validate, compute, or refuse the write. Property Get is the read gate, Property Let receives a value, and Property Set receives an object. Mixing up Let and Set is the number-one error; leaving out Let on purpose is how you make a field read-only.

' --- Inside a class module (clsEmployee) ---
Private mSalary As Currency          ' the backing field, hidden from the outside

Public Property Get Salary() As Currency   ' READ gate
    Salary = mSalary
End Property

Public Property Let Salary(ByVal value As Currency)   ' WRITE-a-value gate
    If value < 0 Then Err.Raise 5, , "Salary cannot be negative"
    mSalary = value                  ' validated before storing
End Property

' --- Usage reads exactly like a plain field ---
' emp.Salary = 65000   -> runs Property Let (validates, stores)
' Debug.Print emp.Salary -> runs Property Get (returns mSalary)
' emp.Salary = -100    -> raises "Salary cannot be negative"

A class module can expose its data as plain Public variables — and sometimes that's the right call. But the reason classes feel more solid than a bag of public fields is Property procedures: they are the hook where you decide what the outside world is allowed to do with each field.

What you'll learn

  • The mental model — a gate on a field, not a raw variable
  • Why a Property beats a plain Public variable
  • Get, Let and Set — and the one distinction everyone trips on
  • The backing-field pattern that makes it all work
  • How to make a read-only property (and why that's a feature)
  • When a plain Public variable is the honest choice

The mental model: a gate on a field

A Property is a gate in front of a field. To anyone using your object it looks identical to a normal variable — they write emp.Salary = 65000 and read x = emp.Salary — but each of those touches runs a small procedure you wrote. The read runs Property Get; the write runs Property Let (for values) or Property Set (for objects).

That indirection is the entire point. Because your code sits in the gate, you can check the value before storing it, compute a value that isn't stored at all, or simply not provide a write gate so the field becomes read-only. The caller never has to know — the syntax is the same either way.

Why a Property beats a plain Public variable

A Public field is a hole straight into your object: anyone can write anything, any time, with no checks. emp.Age = -5 succeeds. emp.Id = 999 overwrites an identity that was supposed to be permanent. There is no place to put a rule, because there is no code between the caller and the field.

A Property gives you that place. The failure it prevents is the silent bad write — the negative age, the salary set to a string that later blows up a calculation, the "unique" id quietly reassigned. With a Property Let, the illegal write is caught at the point it happens, with a clear message, instead of surfacing three procedures later as a mysterious wrong result.

Get, Let and Set: the one distinction everyone trips on

There are three property procedures, and the split between the two write ones is the classic VBA stumbling block:

Procedure Direction Receives / returns Use for
Property Get Read Returns a value or object Reading any property
Property Let Write Receives a value (Long, String, Date, Currency…) Writing a value property
Property Set Write Receives an object (Range, class instance…) Writing an object property

The rule is the same one that governs ordinary assignment in VBA: values use Let, objects use Set. If a property holds a Range and you write a Property Let for it, assigning emp.HomeCell = Range("A1") fails, because assigning an object needs Set — and VBA looks for a Property Set it can't find. Match the procedure to the kind of thing the field holds:

Private mRange As Range

Public Property Get HomeCell() As Range
    Set HomeCell = mRange          ' note: Set, because we return an object
End Property

Public Property Set HomeCell(ByVal r As Range)   ' Set, not Let — it's an object
    Set mRange = r
End Property
' Usage:  Set emp.HomeCell = Range("A1")

Notice that even inside Property Get, returning an object uses Set HomeCell = .... The Let/Set distinction follows the kind of data, everywhere.

The backing-field pattern

Properties almost always come in a pair wrapped around a hidden field. The field is Private (the m prefix is convention for "member"), and the world reaches it only through the gates:

Private mName As String                    ' hidden backing field

Public Property Get Name() As String
    Name = mName
End Property

Public Property Let Name(ByVal value As String)
    mName = Trim$(value)                    ' normalise on the way in
End Property

This is the shape that makes encapsulation real: the data lives in one Private variable, and every read and write goes through code you control. Change how a name is stored later — trimmed, upper-cased, validated against a list — and you change one Property Let, not every caller.

How to make a read-only property (and why that's a feature)

Leave out the Property Let and the field becomes read-only from the outside: the class can set the backing field internally, but callers can only read it.

Private mId As Long

Public Property Get Id() As Long     ' Get only — no Let
    Id = mId
End Property

Friend Sub AssignId(ByVal newId As Long)   ' class sets it internally
    mId = newId
End Sub
' emp.Id            -> works (read)
' emp.Id = 42       -> compile error: Can't assign to read-only property

That compile error is not an obstacle — it's the guarantee. A read-only property is how you express "this value is set once and never edited," and the compiler enforces it for you. The same technique gives you computed properties that have no backing field at all:

Public Property Get FullName() As String
    FullName = mFirst & " " & mLast        ' derived, nothing stored
End Property

When a plain Public variable is the honest choice

Here's the judgement that separates good VBA from cargo-culted boilerplate: not every field needs a Property. If a field never needs validation, never needs to be computed, and is fine to read and write freely, then a Public variable says exactly that — and wrapping it in a pass-through Get/Let pair that does nothing but copy mX back and forth adds noise, not safety.

So: reach for a Property when you have a reason — validation, a read-only id, a computed value, an object field that needs Set. For a plain, unconstrained value, a Public variable is the honest, readable choice. Add the gate when you need the gate; don't build gates around open fields.

How ExcelMaster helps

The property rules are small but unforgiving: Let for values, Set for objects, a missing Let for read-only, a Private backing field behind each pair. Get the Let/Set pairing wrong and it won't compile; get the encapsulation wrong and your "protected" field is wide open.

ExcelMaster writes the whole shape for you. Describe the object — "an Employee whose salary can't be negative, with a read-only id and a computed full name" — and it generates the Private backing fields, the validating Property Let, the object-aware Property Set where needed, and the Get-only read-only properties, all paired correctly. You get proper encapsulation without memorising which keyword goes with which kind of field.

Frequently asked questions

What is a Property in VBA?

A Property is a procedure in a class module that controls access to a field. Property Get runs when the field is read, and Property Let (for values) or Property Set (for objects) runs when it's written. To the caller it looks like a normal variable — emp.Salary = 65000 — but your code runs behind the assignment, so you can validate, compute, or make the field read-only.

What is the difference between Property Let and Property Set?

Property Let receives a value — a Long, String, Date, Currency, and so on. Property Set receives an object — a Range, a class instance, or any reference type. It's the same rule as ordinary assignment: values use = (via Let), objects use Set (via Set). Using Let for an object property, or Set for a value, is a compile or run-time error.

How do I make a read-only property in VBA?

Write a Property Get but no Property Let (or Set). Callers can then read the value but not assign to it — an attempted write is the compile error "Can't assign to read-only property." The class itself can still change the backing field internally. This is ideal for identity values that are set once, or for computed properties like a full name derived from other fields.

Why use a Property instead of a Public variable?

A Public variable can be written with any value, any time, with no checks. A Property gives you a place to validate input, compute a value, make a field read-only, or change how the data is stored later without touching callers. Use a Property when you have such a reason; for a plain unconstrained value, a Public variable is simpler and perfectly honest.

What does Property Get do in VBA?

Property Get is the read side of a property: it runs whenever code reads the property, and it returns the value (or, for an object property, returns it with Set). It's typically paired with a Property Let or Set for writing, wrapped around a Private backing field — but a Property Get on its own creates a read-only or computed property.

Tested in

Tested in: Excel 365 (Windows 11), VBA 7.1 — last verified 2026-08-04.

Related guides: VBA Class Module · VBA Type · VBA Dim · VBA Function · VBA ByRef vs ByVal