Simple Things Pt.1: Values

Sometimes, simple things are just very effective abstractions that are very good at hiding the giant rabbit hole underneath.

Like an innocent little literal value for example:

Debug.Print 42

This 42 is just that, a plain integer value – isn’t it?

One could reasonably set out and write a parser that produces an abstract syntax tree (AST) here that would include some LiteralExpression node, that necessarily evaluates to 42.

But the node itself isn’t the value. In fact – perhaps surprisingly – it doesn’t even know what or where that value is. It knows where it is defined in the source code, but that’s not what I meant with where that value is.

So where does the 42 actually live? Where is it stored? And why does it even matter?

The answer is… not in the expression node: the node evaluates to a value, but is not that value.

For starters, the specifications dictate that 42 must be an Integer literal. Not a Long, not a Double – although a different value might yield either semantic data type. The grammar however, only distinguishes integer numbers from floating-point numbers: it’s token semantics specified in MS-VBAL that ultimately determines the semantic data type.

It also states very plainly that an integer value should be a 16-bit signed integer, and also defines such internal representations for each intrinsic data type: clearly we can’t just make everything a double and run with it, or we’ll almost certainly break something downstream.

Why is that?

More Than Values

If we stop and think about the type system in VBA, we quickly realize that we don’t just need values for literals, and that many other things evaluate to, or represent a value – like functions, parameters, and if we squint a little even a class instance (object) could be coerced into a value.

And that’s a problem if we model a semantic type system that embeds values directly, because then the assignment of a ByRef parameter can only behave as a value, not as a reference. Besides we also want to be able to represent values that exist and must be usable but aren’t defined anywhere in source code.

This is why RDCore introduced binding handles as an indirection layer between a VBTypedValue and the underlying binary value it represents.

Back to the literal 42 integer value: we have a value binding that yields the 42, and so the VBIntegerValue type knows it has a binding that can get the value, and it doesn’t need to know where that value actually is.

An integer parameter passed by reference would also be a VBIntegerValue, but its binding would be a reference binding rather than a value one, likely pointing to a symbol defined somewhere in the call stack: changing the value of this reference binding would necessarily affect the value everywhere it’s referenced, because its runtime value is associated to its declaration symbol within the program memory.

The RDCore semantic type system explicitly differentiates types and values, such that a VBIntegerValue represents a value of type VBInteger. This is slightly different from other models, where a value might be an instance of a given data type. Beyond that, a type might also be described by a value that represents a data type: VBTypeDescValue. This special meta-value is useful in a number of scenarios (notably TypeOf operators), and enables reflection-like capabilities and semantics that may or may not end up exposed at the language level, possibly through platform extensions.

This differentiation is necessary to correctly model arrays, UDT, and custom class types – that’s a whole other rabbit hole that deserves its own post, but for now this is what matters:

VBInteger:VBType
👇describes
VBIntegerValue:VBTypedValue
👇bound to
42:System.Int16

If an instance of a given VBType represented a value of that type, then we would need to generate the complex types on the fly, and that would be way more complicated than things need to be: we don’t need dynamic types when everything is statically defined – what we need is just a model that makes it work, and conceptually separating data types from typed values does exactly that.

Runtime Values

The RDCore SDK defines an entire type system that supports everything (and more!) VBA can do, using .net types to represent all underlying runtime values.

While several data types work pretty well as-is, others like Boolean, Currency, and Decimal don’t really map 1:1 and need a special type that correctly represents the value. For example an Integer value easily maps to a .net Int16, but mapping a .net Boolean to a VBA Boolean would introduce bit alignment issues (notably in UDT types), because it’s a 16-bit integer under the hood but a .net Boolean is only a single byte! Decimal is another, perhaps less consequential since it’s not declarable, but MS-VBAL specifies it as fitted across 14 bytes (3x Int32 +Int16), yet the corresponding .net type is 16 bytes wide (4x Int32); Variant is another data type that needs its own interop value, a 24-byte struct that can hold anything, value or reference.

The Debug.Print 42 instruction parses the 42 as a literal expression that evaluates to a VBIntegerValue that has a ValueBindingHandle that holds the managed Int16 value 42.

If it were Debug.Print “Hello, world!”, we would’ve had a VBStringValue with a ReferenceBindingHandle instead, holding a reference to a managed string holding the literal value. Concretely, this means a reference binding is really just a wrapper around a managed object; this makes it possible to box value types and use them as references in ByRef scenarios.

But it’s just a literal!

And it is. But to be useful, the semantic model must be able to tell a Variant from a Long from a Double, and a unified semantic type system that doesn’t care whether a value came from source code or is the result of an operation, and isn’t concerned about the internal memory representation of that value: that’s what the semantic model abstraction level does, and that’s where the AST belongs.

Constantly wrapping and unwrapping runtime values into semantic ones would be terribly inefficient, for run-time though. If it doesn’t sound so bad, try looping a million times into an array and adding one to each element, and the overhead should become obvious: it’ll interpret nodes all right, but something else must be able to actually run things without caring for the semantic layer.


Progress Status

As of this writing, the parser produces an AST containing all the expected nodes in an initial declaration pass: module directives and attributes, as well as everything in the declarations section, and procedure member signatures (including parameters) – but no executable statement nodes yet, although many of these have already been defined.

These nodes will be introduced in the AST alongside their respective evaluation semantics in an evaluation engine that’ll become the interpreter that will eventually evaluate nodes in break mode, while a separate execution engine will operate at a lower level, working directly with the underlying runtime types.

This will all be tested and benchmarked (and adjusted as needed) in due time, of course.

For now the development focus is turning to the LSP client/server SDK, which is what underpins cross-process communications across the entire RDCore platform. Once that’s in place, the language server can start implementing LSP handlers that an IDE can use, for everything a declaration pass already unlocks – but that work will be ticketed and not completed right away (not by me anyway), because then focus will have to shift to the semantic evaluation engine and the statement nodes, because GoTo and GoSub/Return, not to mention error states, are an interesting twist on what would otherwise be a rather straightforward AST traversal.

VIVAT CUCUMIS

(English below)

Longue vie au concombre

Le 26 mai 2026 marquera le 10e anniversaire de la découverte par le contributeur historique @Comintern de ce message cryptique à la clé de resource 18089 de la librairie VBE7INTL.DLL:

STRINGTABLE
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
{
18080, "Tile Horizontally"
18081, "Tile Vertically"
18082, "Arrange Icons"
18083, "Microsoft Visual Basic for Applications Help Topics"
18084, "Search Reference Index..."
18085, "Obtaining Technical Support"
18088, "About Microsoft Visual Basic for Applications..."
18089, "Long Live the Cucumber"
18090, "Break On All"
18091, "Break In Ole Server"
18092, "Break On Unhandled"
}

Le projet Rubberduck a toujours voulu s’approprier cette phrase et s’en servir quelque part d’une façon ou d’une autre.

Rubberduck Core marine ce concombre depuis un certain temps, et fait de cette phrase son slogan, en latin:

Gravé dans la pierre, VIVAT CUCUMIS se lit en latin comme une prophétie ancienne.

Il y a plusieurs niveaux à cette imagerie: plongeons.

Gravé dans la pierre

Quand on dit de quelque chose qu’il est gravé dans la pierre, on décrit quelque chose d’immuable, ou qui n’est pas prêt de changer. Un peu comme les spécifications d’un certain langage de programmation.

La pierre taillée évoque l’antiquité et la renaissance, mais aussi les pierres tombales et les cimetières, où l’on pourrait s’attendre à retrouver une langue morte comme le latin… ou VBA. Ça dit “ceci existe depuis longtemps”, mais aussi “ceci fait partie de notre héritage”.

La pierre est une fondation solide, noble. Elle est aussi lourde, et peut être un fardeau tout comme le code hérité – ou pour Microsoft tout comme le support des librairies d’exécution de VBA. Elle dit malgré tout “ceci existera encore longtemps”.

VBA est mort, vive VBA!

Peut-être que le proverbial concombre se voulait réellement référer à Visual Basic même, mais c’est sans importance de toute façon parce que VBA a effectivement survécu, et donc le soulier fait, même si c’est a posteriori.

L’utilisation d’une image qui pourrait être interprétée comme une pierre tombale pour quelque chose qui est lié à VBA assume complètement la nature “intuable” du langage et la profonde ironie de le voir survivre à chaque produit ou technologie qui tente désespérément et successivement de le remplacer : VBA est mort, longue vie à VBA!

Modernisation

Rubberduck Core conserve les racines et fait évoluer le concept, alors on passera éventuellement de la pierre au métal – à l’acier :

Gravés au laser sur un médaillon en acier, les mêmes mots deviennent à la fois un hommage, une promesse, une réalisation, un… porte-clé sans doute.

L’acier est toujours la pierre, en quelque sorte. Cuisinée un peu certes (bon d’accord, carrément séparée du métal…), mais néanmoins il vient de la pierre. Brute, lourde et difficile à manier, maintenant raffinée, élégante et polie, relativement légère mais robuste et durable. Et brillante aussi. L’âme y est clairement toujours.

C’est précisément ce qui va se produire avec Rubberduck : le concombre ne fait que mariner encore un peu… parce qu’une décennie plus tard, celui-là n’est toujours pas un cornichon.

rubberduckvba.ca

Le site historique du projet rubberduckvba.com redirige désormais vers rubberduckvba.ca et le dépôt du projet Rubberduck sur GitHub est maintenant archivé en lecture seule. Les efforts de développement pour la prochaine évolution sont en cours dans un dépôt pour l’instant privé sous la même organisation rubberduck-vba; Rubberduck Core en sera bientôt le nouveau projet-phare en mode Open-Core, soutenu par 9562-7303 Québec inc., une société privée fondée à cet effet par le même auteur principal de Rubberduck et auteur de ce blogue depuis son commencement.

Être incorporé au Québec signifie que toutes les communications officielles seront publiées dans ce format en français d’abord, avec un lien immédiat vers le contenu équivalent en anglais. Ça signifie également que la disponibilité du contenu dans une langue autre que l’anglais n’est pas un ajout, mais une nécessité : tout comme Rubberduck, Rubberduck Core (ou RDCore pour faire plus court) sera assurément disponible en français et en anglais dès le jour un, et ensuite dans toutes les langues que la communauté rendra disponibles. Ce n’est pas un fardeau, mais une opportunité. Vos documents seront toujours envoyés dans la langue de votre choix.

(C) 2026 Mathieu Guindon pour 9562-7303 Québec inc.


English

Long Live the Cucumber

May 26, 2026 will mark the 10th anniversary of the discovery by core historical contributor @Comintern of this cryptic message at resource key 18089 of the VBE7INTL.DLL library:

STRINGTABLE
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
{
18080, "Tile Horizontally"
18081, "Tile Vertically"
18082, "Arrange Icons"
18083, "Microsoft Visual Basic for Applications Help Topics"
18084, "Search Reference Index..."
18085, "Obtaining Technical Support"
18088, "About Microsoft Visual Basic for Applications..."
18089, "Long Live the Cucumber"
18090, "Break On All"
18091, "Break In Ole Server"
18092, "Break On Unhandled"
}

The Rubberduck project always wanted to appropriate this phrase and use it somewhere, somehow.

Rubberduck Core marinates the cucumber and makes the quote its catchphrase, coined in Latin:

Carved in stone, Latin VIVAT CUCUMIS reads like some ancient prophecy.

There are a few layers to this imagery: let’s dive.

Carved in Stone

When we say something is carved in stone, we are describing something that is either immutable, or isn’t about to change – much like the specifications of a certain programming language.

Carved stone evokes Antiquity and Renaissance, but also cemeteries and headstones, like where you would expect to find a dead language like Latin… or VBA. It says “this has been around for a long time”, and also “this is part of our heritage”

Stone is rock solid, foundational, noble. It’s also heavy, and it can be a burden, like legacy code – or if we ask Microsoft, like runtime support for VBA. It nevertheless still says “this will be around for a long time”.

VBA is Dead, Long Live VBA!

Maybe “the cucumber” really did refer to Visual Basic itself, but it wouldn’t matter if it didn’t: VBA lived on, so the shoe fits even if a posteriori.

Using something that can be construed as a headstone to depict something related to VBA leans heavily onto its “unkillable” nature and the profound irony of it surviving every single one of its successive replacement attempts: VBA is dead, long live VBA!


Modernization

Rubberduck Core keeps the roots and evolves the concept, and so we will eventually grow out of stone, to metal – to steel:

Laser-engraved on a steel medallion, the same words become a tribute, a promise, a fulfillment, a… keychain, perhaps.

Steel is still the stone, in a way – crushed and cooked (narrator: fully separated from it, actually), but it came from the stone. Crude, heavy and unwieldy, it ultimately becomes refined, elegant and polished, relatively lightweight but extremely solid and reliable. And shiny. The soul is still there.

That’s exactly what’s going to happen with Rubberduck – the cucumber is only marinating a little longer… because a decade later, this one still hasn’t pickled yet.

rubberduckvba.ca

The historical project site rubberduckvba.com is now redirecting to rubberduckvba.ca and the Rubberduck repository on GitHub is now archived/read-only. Development efforts towards the next evolution are currently in progress in a private repository under the same rubberduck-vba organization; Rubberduck Core will soon be its flagship Open-Core project under 9562-7303 Québec inc., a private company founded for this specific purpose by the same primary author of Rubberduck and of this blog since its inception.

Being incorporated in Québec means all public communications are going to be issued in a French-first format, with an immediate link to the English content. It also means that localization isn’t an afterthought in this company, but a necessity: like Rubberduck before it, Rubberduck Core (or RDCore for short) shall be assuredly available in both French and English, and then every language it would end up being translated into. It’s not a burden, but an opportunity. Your documents will always be emailed in the language of your choosing.

(C) 2026 Mathieu Guindon on behalf of 9562-7303 Québec inc.