twinBASIC Update: October 7, 2025

Highlights include a bombshell unexpected major feature release (full OOP support!!!) and a twinBASIC XAML control-based media player.

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:


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.

Releases · WaynePhillipsEA/twinbasic
Contribute to WaynePhillipsEA/twinbasic development by creating an account on GitHub.

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, and Protected 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:

Raising Custom Events in VBA
This quick tutorial will have you writing custom events in VBA in no time.

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

All original code samples by Mike Wolfe are licensed under CC BY 4.0