10 PRINT "Hello, QBasic nostalgia!"

16 Aug 2020

Categories: Code Tags: QBasic Learning Nostalgia

Somewhere in the depths of my hard drive is a folder named “Archive”. It’s a home for all sorts of files that I no longer need, but can’t quite bring myself to delete. Old homework assignments from high school, revisions 1 through FINISHED-FINAL.doc. MSN chat logs, preserving conversations with people I’ve not spoken to in 10 years. Random low-resolution photos of not very much, shot with the first digital camera my family ever owned. Layers of backup directories piled above the deposits of those before them, poised to restore devices long since sold on eBay. A veritable time capsule of my digital life.

Not something I pry open the lid on very often, but lockdown-induced nostalgia enticed me to visit again a few weeks ago. I was in search of the roots of my journey in programming. I found them inside a dormant virtual machine, the ghostly continuation of an old family computer that I had immortalised in .vmdk form.

Firing up VirtualBox, I went digging.

Book cover: Mallard BASIC Introduction and Reference


It all started about 16 years ago. I was already a proficient user of technology in general, as most computer game-obsessed teenagers are wont to be. My initial motivation for skilling up was quite simple, albeit ambitious: I wanted to be able to “hack” a certain online game. Luckily, I wasn’t expecting quick results and soon lost sight of this nefarious goal to discover the joy of programming as something in itself.

My Grandad had on several occasions previously attempted to enthuse me in the subject, to no avail. Now, excited that I was finally displaying interest of my own accord, he provided me with a floppy disk containing QBasic 1.1 and a manual for Mallard BASIC. I started at page 1 and worked my way through the book — as far as the difference in dialect between QBasic and Mallard BASIC would allow, anyway.

First step into a larger world

Safe to say, it took me a while to get enough of a hang of things before I could really begin to translate ideas from my imagination onto screen. The first game I created was Asterix[sic] 9. It was probably also my first “substantial” program, built with other users in mind, not just for myself.

Screen capture showing playthrough of Asterix 9, a simple maze puzzle game

Asterix 9 went through many rewrites as I discovered more and more programming concepts. The debut version is written almost as if parodying the worst kind of BASIC program: I had not yet realised that QBasic did not require every line to be numbered (as the Mallard BASIC book would have me believe!), and concepts like arrays, looping, functions, and DRY were still very much unknown to me. The liberal use of GOTOs makes it very spaghetti-esque, not helped by non-existence of human readable labels. Every level of the game is just a copy-and-paste of the previous level with line numbers incremented (this used to take me hours of “refactoring”). It’s truly awful. I’d be lying, however, if I said I didn’t have an absolute blast figuring out how to code it, at the time.

Here is an excerpt of part of the game loop that checks teleportation and collision into one of the “9"s:

4161 IF currx% = 4 AND curry% = 8 AND count1 < 1 THEN GOTO 4550
4162 IF currx% = 14 AND curry% = 18 AND count2 < 1 THEN GOTO 4680
4163 IF currx% = 20 AND curry% = 14 AND count3 < 1 THEN GOTO 5100
4164 IF currx% = 12 AND curry% = 12 AND count4 < 1 THEN GOTO 5230
4165 COLOR 5
4166 IF count1 < 1 THEN LOCATE 4, 8: PRINT CHR$(176)
4167 IF count2 < 1 THEN LOCATE 14, 18: PRINT CHR$(176)
4168 IF count3 < 1 THEN LOCATE 20, 14: PRINT CHR$(176)
4169 IF count4 < 1 THEN LOCATE 12, 12: PRINT CHR$(176)
4170 count = count + 1
4180 IF currx% = 4 AND curry% = 6 THEN GOTO 9300
4190 IF currx% = 4 AND curry% = 12 THEN GOTO 9300
4200 IF currx% = 6 AND curry% = 6 THEN GOTO 9300
4210 IF currx% = 6 AND curry% = 8 THEN GOTO 9300

Evolution via emulation

I’ve always had an urge to learn how things work from the ground up, and this endeavour was no different. A lot of my effort was spent exploring how programs that I was familiar with might have been implemented.

As I got the hang of ASCII text manipulation and interacting with devices other than the screen, I created a simple word processor. I had not yet discovered mouse controls, so it was entirely keyboard-driven, including the menu options. It was able to save and load a custom rich text format that included support for different colours (the 16 supported in SCREEN 0 mode).

Implementing word wrap in this setting was among my proudest achievements up to this point!

Screen capture showing writing a document in 'word processor'

I also wrote an “encoder” version that “encrypted” its document, and could load and decrypt documents stored on disk. The only problem was that it used an approximately 6-bit key, which in any event was stored inside the encrypted file — thankfully I know a bit more about security today!

Screen capture showing encrypting and decrypting a message in 'encoder'

These programs were at least several steps up in quality from that first version of Asterix 9. I’d learned that labels weren’t mandatory for every line, and they could be human-readable. I’d also learned a few more control flow patterns and how to use DATA to encode blocks of data outside of the code. Young me still very much could have benefitted from reading Clean Code, however!

TYPE encryption
        enco AS INTEGER
        encryptnu AS INTEGER
        length AS INTEGER
DIM code AS encryption
encrypt = INT(RND * 45) + 3
OPEN filename$ FOR RANDOM AS #1 LEN = LEN(code)
code.encryptnu = encrypt
code.length = l
PUT 1, 1, code

My fascination with wanting to build things from scratch eventually reached its logical conclusion: I wanted to create my own operating system1.

My first attempt at this was named “CharnOS”, based on my internet alias at the time2. Really it was just a window manager, but I didn’t yet know the difference. All the “apps” were full screen and the cursor was operated using arrow keys — I still hadn’t worked out mouse support.

Screen capture showing the 'desktop' of CharnOS. Icons for various apps are visible, include word processor, calculator, draw, and My Files.

Discovering community

It was around this time that I found Pete’s QBasic Site and the information, forums, and community within. This was a goldmine! I met a few people there and got to know them via MSN. Some of them effectively became my mentors. My rate of learning skyrocketed, and I got my hands on QBasic 7 which included library support for mouse input and the ability to compile to EXE, among other exciting features.

My operating system aspirations continued, now with mouse support. Version 2, renamed to “Nebula”, was the most complete. It featured moveable windows, various types of UI widget, and multi-user support. The visual style was borrowed from an aforementioned mentor’s own creation.

Screen capture showing logging in to Nebula window manager, and running the jotter text editor app. It's reminiscent of Windows 9x and also very slow.

Following this, I began to discover more modern programming languages like C, C++, PHP, and C#. I began to recognise that I’d really hit the limits of QBasic and that my journey would have to continue on more modern platforms. The Win32 API would prove to heavily inspire version 3 of Nebula, which had a slightly more mature look. It got about this far before I abandoned it, and set my sights on other things.

Screen capture showing Nebula window manager version 3, even more reminiscent of Windows 9x

That said, I would still occasionally dip into QBasic—even years later—for fun graphical demos, like this fire simulation:

Screen capture showing an animation of fire that starts at the bottom of the screen and slowly spreads upwards

When I could make do with VGA graphics, QBasic was still the lowest code-to-pixel barrier of any of the programming languages I knew. And perhaps it still is. In how many other languages is it possible to set up a blank canvas and draw a pixel in literally only two lines of code?

PSET (20,20), 100

QBasic as a learning experience

If there’s a point to this post beyond self-indulgence, it might be to reflect on how QBasic fared as a learning experience for someone new to programming. I’m not saying we should consider encouraging beginners to take their first steps in DOSBox—from which the world had arguably moved on, even at the point when I started—but maybe there are some aspects of the experience that we can learn from.

QBasic was a safe and accessible sandbox for beginner me to explore my creativity within. I’m sure there are modern alternatives that offer similar experiences, I just haven’t been on the lookout for them. It’s impossible for me to exactly re-envisage the perspective that started me on this journey 16 years ago. Sure, I still find coding and solving problems to be fun, but never in quite the same way as I did back then, when everything was new and exciting.

Convenience is a double-edged sword. The QBasic IDE hides a lot of complexity from the programmer. I didn’t need to worry about compiling, or linking, or the command-line in general. Double-clicking QBX.EXE would drop me instantly into the action, ready for me to just start writing and running code. The language itself is also purposefully, well, basic. There’s relatively little “structural syntax”, for lack of a better term, and the IDE even attempts to hide some of that. I think this was beneficial to begin with, but increased the learning curve when I eventually moved on to languages with a lot of structural syntax like C and C#. I still remember being utterly baffled by the arcane incantations of a C “hello, world”: what on Earth does any of void main(int argc, char *argv[]) mean?!

These would have been learning curves no matter what, but I feel that delaying them until later meant I was able to make quicker progress. I would have been much less inclined to bash my head against walls like linker errors if I wasn’t already hooked. And of course, even if today’s mainstream languages might have a higher barrier to entry than in the past, this is offset by the convenience of finding help. Tutorials, documentation, books, Stack Overflow: there is so much more support available to beginners now.

What motivated me is certainly not going to apply to everyone. In hindsight, luckily, QBasic worked as my first programming language because it turned out I was motivated by the art of programming in itself, and at the beginning I just wanted to have fun. Had I instead wanted to create a website to share with people, or a mobile game to sell on the App Store, it would have been the wrong choice and I would have become frustrated.

It’s for this reason that I don’t think there’s a universal perfect programming language for beginners. It matters more that they start with something that helps them make visible and meaningful progress towards their goal. Find out what excites them first, and get them started on a toolset based on that. There will always be time to learn more, later.

Finally, I think this applies regardless of what stage your life or career is at. Your goals and motivation will change over time, and you should adapt your learning plan to fit. Take a step back, think about what you really want, and set a course for that outcome.

  1. I still do, and might give it another try some day. Until then I’ll be content to live vicariously through Andreas Kling’s SerenityOS↩︎

  2. I was a big fan of C. S. Lewis, from whose work I got the name↩︎