twinBASIC Update: October 7, 2025
On April 23, 2021, I helped Wayne Phillips introduce the world to twinBASIC at the Access DevCon Vienna conference. I boldly predicted that twinBASIC (along with the Monaco editor) would replace VBA and its outdated development environment by 2025. With that goal in mind, this weekly update is my attempt to keep the project fresh in the minds of the VBA development community.
Every Sunday Monday week, I will be providing updates on the status of the project, linking to new articles discussing twinBASIC, and generally trying to increase engagement with the project. If you come across items that should be included here, please leave a comment below.
Here are some links to get involved with the project:
- Custom twinBASIC IDE Installation Guide
- twinBASIC Discord Server (chat about the project)
- twinBASIC Wiki (list of new features not in VBx)
- GitHub Issue Tracker (report bugs)
- twinBASIC/VBx LinkedIn Group
Highlights
Full OOP Support Added!
In a surprise feature drop, BETA 876 added experimental support for full object-oriented programming, including:
- Overrides
- Multiple inheritance
- Explicit base class constructors
- Protected members
There's also a new sample project–Sample 23. OOP Inheritance Example (Animals)–that demonstrates the syntax and allows you to see these concepts in action.
Here's an excerpt from the Main module's header comment:
' Example: Object-Oriented Inheritance in twinBASIC
'
' This example demonstrates the key features of twinBASIC's class inheritance system.
'
' The sample defines a small hierarchy of Animal classes:
' Animal → Dog → GuardDog
' → Cat
'
' It illustrates how:
' • The "Inherits" statement allows a derived class to reuse and extend the functionality of its base class.
' • Fields and procedures declared as "Protected" are accessible to derived classes, but not to external code.
' • Methods in a base class can be declared "Overridable", allowing subclasses to provide new implementations.
' • Derived classes replace base implementations using the "Overrides" syntax.
' • Inherited events (e.g., Spoke) can be raised from base or derived classes and handled externally.
The feature was fast-tracked to help with the rewrite of certain core components (e.g., the built-in UI controls). This should improve the long-term maintainability of the twinBASIC code base.
Based on my cursory review, it appears this new feature introduces the following new keywords into the language:
Inherits
Protected
Overrides
Overridable
See the end of this article for a full reproduction of the source code from the new sample project to see these new keywords in action.
Discord Chat Summary
* Auto-generated via Claude-Sonnet-4.5
Overview
This week brought a major surprise with the early introduction of experimental class inheritance in beta 876, a feature originally planned for a later release. The update enables full OOP capabilities including overrides, multiple inheritance, and protected members. Meanwhile, technical discussions centered on debugging a complex x64 calling convention issue with PreserveSig Double returns, and community members explored new media playback capabilities using XAML controls.
Language Enhancements
- waynephillipsea announced the early release of experimental class inheritance support, enabling full OOP with overrides, multiple-inheritance, explicit base class constructors, and Protected members
- The inheritance feature was introduced ahead of schedule to allow rewriting core components (like built-in UI controls) using true inheritance, removing internal hacks previously needed with Implements-Via
- A new Sample 23 (OOP Inheritance Example - Animals) was added to demonstrate the inheritance capabilities
- Community members noted the significance of this update, with sokinkeso highlighting how it gives "new shape to twinbasic"
Bug Fixes & Improvements
- fafalone identified and waynephillipsea diagnosed a critical x64 calling convention bug where PreserveSig Double returns were incorrectly using the x87 FPU stack (
fstp
) instead of XMM0 registers - The issue affected all PreserveSig methods returning Double types while other return types (BOOL, Integer) worked correctly
- Through systematic debugging with WinDbg and assembly analysis, the team determined the compiler was hitting an old branch that never got upgraded to x64
- Non-PreserveSig Double returns and 32-bit implementations were unaffected by the issue
Community Development
- deletedewd demonstrated a fully-featured media player implementation using the XAML MediaPlayerElement control, showcasing ease of use and rich functionality
- Discussion touched on the value of Implements-Via as a potential alternative to traditional multiple inheritance limitations found in C# and VB.NET
- mansellan suggested Implements-Via might function similarly to mixins, offering a better approach to composition than laboriously "passing through" interface members
Conclusion
The unexpected early arrival of class inheritance marks a significant milestone in twinBASIC's evolution toward full OOP support. While this feature enables cleaner internal architecture and removes previous workarounds, the resolution of the x64 PreserveSig Double bug demonstrates the ongoing refinement of the compiler's native code generation. The community continues to explore twinBASIC's capabilities through practical implementations like media players, while thoughtful discussions about language design choices like Implements-Via show the project's commitment to learning from both VB6's legacy and modern language innovations.
Around the Web
twinBASIC XAML Media Player
From VanGoghGaming's show-and-tell post titled, "Simple Media Player with the XAML MediaPlayerElement Control":
In this project we are using the XAML MediaPlayerElement control to play various media files. It has built-in controls for selecting Volume, Casting to other devices, Aspect Ratio and other metadata properties that may be present in the file (such as Subtitles, Director Commentary, etc). The project is also showcasing the FileOpenPicker class to show a modern interface for selecting files (double-click on the form to start).
Download it from this vbForums thread.
Changelog
Here are the updates from the past week. You can also find this information by visiting the GitHub twinBASIC Releases page.
AI-Generated Changelog Summary
* Auto-generated via Gemini-2.5-Pro, sorted in order of its opinion of "most impactful changes."
Major New Features
- Object-Oriented Programming with Class Inheritance: Experimental support for full OOP has been introduced, including class inheritance with
Inherits
, method overrides, multiple inheritance, explicit base class constructors, andProtected
members. This feature was accelerated from a later planned release to enable rewriting core components (like built-in UI controls) using true inheritance, eliminating previous internal workarounds and improving stability, maintainability, and performance.
Significant Improvements
- Debug Console Performance: Fixed latency issues in the Debug Console window that caused slower output display when multiple
Debug.Print
statements executed in quick succession, and resolved slow rendering on some systems.
Notable Bug Fixes
-
ActiveX Control Mouse Events Crash: Fixed a critical regression from Beta 874 that caused hard crashes when clicking on ActiveX controls (such as ListView from MSComctlLib) during Mouse events.
-
IDE Add-ins Loading: Restored functionality for IDE add-ins stored in the shared common folder (%APPDATA%\twinBASIC\addins), which were not loading since Beta 874.
-
FPU Value Handling: Corrected code generation for interface members using
[PreserveSig]
that return floating-point values (Single/Double/Date) on Win64 platforms.
WARNING: The following issues are present in each of the releases below:
- IMPORTANT: This is an interim/experimental release. It includes significant changes, so some instability is to be expected.
- KNOWN ISSUE: Controls are not being destroyed properly by the form designer, causing big memory leaks (broken in this build)
BETA 876
- fixed: using [PreserveSig] on an interface member returning an FPU value (Single/Double/Date) would not produce correct codegen when called on Win64 [ fafalone, discord ]
- fixed: (regression since BETA 874) first run of IDE licence agreement 'ACCEPT' button does not work [ Jan Batka, discord ]
- fixed: (regression since BETA 874) DEBUG CONSOLE latency increased when multiple prints occurred in quick sucession [#2240]
- fixed: (regression since BETA 874) IDE addins stored in the shared common folder (%APPDATA%\twinBASIC\addins) were not being loaded [ Frank-S, discord ]
- fixed: (regression since BETA 874) ActiveX control Mouse events could cause a hard crash at runtime [#2241]
- fixed: IDE modal dialogs no longer incorrectly switch button focus when using arrow keys and focus is on an input element
- added: (experimental) class Inherits support, for full OOP, supporting overrides, multiple-inheritance, explicit base class constructors, and Protected members
- NOTE: full OOP was originally planned for later release; it’s being introduced early to allow us to rewrite core components (such as the built-in UI controls) using true inheritance, in turn allowing us to remove many of the internal hacks previously needed to simulate inheritance with Implements-Via, improving overall stability, maintainability, and performance in the short term
- added: Sample 23. OOP Inheritance Example (Animals)
BETA 877
- fixed: (regression) 'Manage Keyboard Shortcuts' IDE feature would not allow creating a new group
- fixed: a few more IDE modal dialogs incorrectly switch button focus when using arrow keys and focus is on an input element [ Tecman, discord ]
- fixed: DEBUG CONSOLE slow rendering on some systems since BETA 873
Inheritance Example Source Code
For your convenience (and to get the attention of the web crawlers out there), I'm reproducing the source code from Sample 23 below.
If you've never played around with raising custom events in VBA, I wrote a short quick-start guide on the topic several years ago:
Animal.twin
Private Class Animal
Protected _name As String
Protected _dob As Date ' date of birth
Public Event Spoke(ByVal sound As String)
Public Sub New(name As String, dob As Date)
_name = name
_dob = dob
End Sub
Public Property Get Name() As String
Name = _name
End Property
Public Property Get DOB() As Date
DOB = _dob
End Property
' Age in whole years based on DOB and today's date
Public Function AgeYears() As Long
Dim y As Long
y = DateDiff("yyyy", _dob, Date)
If DateSerial(Year(Date), Month(_dob), Day(_dob)) > Date Then y = y - 1
AgeYears = y
End Function
Public Sub Speak()
Dim s As String
s = GetSound()
RaiseEvent Spoke(s)
Debug.Print _name & " says: " & s
End Sub
' --- Overridable hook for derived classes ---
Protected Overridable Function GetSound() As String
GetSound = ""
End Function
End Class
Cat.twin
' ===== Derived: Cat =====
Private Class Cat
Inherits Animal
Public Sub New(name As String, dob As Date)
Animal.New(name, dob) ' we can explicitly call base constructors from within our constructor
End Sub
Protected Function GetSound() As String Overrides Animal.GetSound
GetSound = "meow"
End Function
End Class
Dog.twin
' ===== Derived: Dog =====
Private Class Dog
Inherits Animal
Protected _breed As String
Public Sub New(name As String, dob As Date, breed As String)
Animal.New(name, dob) ' we can explicitly call base constructors from within our constructor
_breed = breed
End Sub
Public Property Get Breed() As String
Breed = _breed
End Property
' Override:
Protected Overridable Function GetSound() As String Overrides Animal.GetSound
GetSound = "woof"
End Function
End Class
GuardDog.twin
' ===== Further derived: GuardDog (Dog → GuardDog) =====
Private Class GuardDog
Inherits Dog
Protected _onDuty As Boolean
Public Sub New(name As String, dob As Date, breed As String)
Dog.New(name, dob, breed) ' we can explicitly call base constructors from within our constructor
_onDuty = True
End Sub
Public Property Get OnDuty() As Boolean
OnDuty = _onDuty
End Property
Public Property Let OnDuty(ByVal v As Boolean)
_onDuty = v
End Property
' Multi-level override (overriding Dog's override):
Protected Function GetSound() As String Overrides Dog.GetSound
If _onDuty Then
GetSound = "WOOF!"
Else
GetSound = "woof"
End If
End Function
End Class
AnimalWatcher.twin
Private Class AnimalWatcher
Public WithEvents D As Dog
Public WithEvents C As Cat
Public Sub New(d As Dog, c As Cat)
Set Me.D = d
Set Me.C = c
End Sub
Private Sub D_Spoke(ByVal sound As String)
Debug.Print "[Watcher] Dog spoke: " ; sound
End Sub
Private Sub C_Spoke(ByVal sound As String)
Debug.Print "[Watcher] Cat spoke: " ; sound
End Sub
End Class
Main.twin
' The demonstration prints output to the Debug console showing polymorphic behavior,
' including multi-level overrides (GuardDog overriding Dog's GetSound).
'
' Run `AnimalsDemoMod.DemoAnimals` to see the example in action.
Module AnimalsDemoMod
Sub DemoAnimals()
Dim myDog As Dog = New Dog("Rex", #10-Feb-2019#, "Labrador")
Dim myGuardDog As GuardDog = New GuardDog("Rover", #01-Jun-2018#, "German Shepherd")
Dim myCat As Cat = New Cat("Misty", #20-Nov-2022#)
Dim watcher As AnimalWatcher = New AnimalWatcher(myDog, myCat)
Debug.Print myDog.Name & " age: " ; myDog.AgeYears()
myDog.Speak
Debug.Print myGuardDog.Name & " age: " ; myGuardDog.AgeYears()
myGuardDog.Speak
myGuardDog.OnDuty = False
myGuardDog.Speak
Debug.Print myCat.Name & " age: " ; myCat.AgeYears()
myCat.Speak
End Sub
End Module
Debug Console Output:
Executing 'InheritanceExample1.AnimalsDemoMod.DemoAnimals'...
Rex age: 6
[Watcher] Dog spoke: woof
Rex says: woof
Rover age: 7
Rover says: WOOF!
Rover says: woof
Misty age: 2
[Watcher] Cat spoke: meow
Misty says: meow