My Photo
Location: Downham Market, Norfolk, United Kingdom

Saturday, December 17, 2016

On the numeric precision provided by programming languages

Probably the most common floating-point format supported by modern programming languages is what C calls a double, that is a 64-bit data type consisting of a 53-bit mantissa, an 11-bit exponent and a sign bit (yes, I know that's 65 bits in all but as is common with floating-point formats the most-significant bit of the mantissa is assumed to be a 1 and isn't stored). More formally this format is standardised in IEEE 754 as binary64.

Some languages provide this as one of a number of different options, for example in C both float (32-bits) and double (64-bits) floating-point formats are commonly supported. In others double is the only floating-point format available; Liberty BASIC is an example of this. The precision provided by this format is sufficient for a wide range of real-world applications; to put it in perspective it corresponds to an uncertainty of about one millimetre in the distance between the Earth and Neptune!

However there is of course a big difference between precision and accuracy. One particularly important issue is that a typical calculation consists of many cascaded steps, and (depending on the kinds of operations performed) at each of these steps there is a possibility that an error of half-an-LSB or more is introduced. After a large number of steps the potential accumulated error may be very much greater than the precision of a double might lead you to expect. For this reason it is common for the 'floating point unit' (FPU) of a modern CPU to work internally to an even higher precision, for example a format with a 64-bit mantissa is often used. So long as intermediate values are held to this higher precision there is a greater likelihood of the final result, represented as a double, having an accuracy commensurate with its precision.

When the highest precision floating-point data type provided by the programming language itself is a double, this desirable outcome can be achieved only when the programmer specifies the calculation in his source code in such a way that it can take place entirely within the FPU, and when the language interpreter/compiler is designed to achieve that. That may be the case in a language like C, when the computation is described in the form of a single expression and the compiler generates code that keeps intermediate values on the FPU stack, but that will not always be the case.

If the programmer's source code splits the calculation into a number of discrete steps, the compiler may not be able to recognise that it could combine them into one computation (and anyway the programmer may want to see the intermediate values to help him debug the code). Even more significantly, an interpreted programming language may simply not be capable of keeping intermediate values in the FPU and may always transfer them temporarily to whatever representation it uses internally for floating-point values. If this is a double a truncation may occur after each step of the calculation.

Of course this may not be important. Many calculations won't need anything like the precision of a 53-bit mantissa and even the loss of several bits of accuracy as a result of multiple truncations may not matter. But sometimes it may, and indeed the programmer may not even know what accuracy is required (if you're not a mathematician - and perhaps even if you are! - it's only too easy to perform a computation in such a way that it is unduly sensitive to the accuracy of an intermediate term, without even realising it).

So ideally there needs to be a way of overcoming the limitation that intermediate values need to be held in the FPU, so that the full accuracy of which the CPU is capable can be taken advantage of even when those values are transferred elsewhere (e.g. to a 'variable'). Some C compilers (notably GCC, but not Microsoft's compilers) support the 80-bit 'temporary float' format as a native data type, when the underlying CPU provides access to it, which solves the problem. By declaring a variable as a long double it can hold an intermediate value with the same precision as that of the FPU's internal registers.

Because the problem is potentially even more acute with an interpreted language, I was very keen that version 6 of BBC BASIC for Windows should have that capability too. Indeed, the default numeric data type is a variant which can contain either an 80-bit floating-point value or a 64-bit integer (it is noteworthy that an 80-bit float can represent a 64-bit integer value precisely). So you can perform cascaded floating-point calculations in BB4W safe in the knowledge that the final result is as accurate as it could be given the capabilities of the CPU/FPU. I don't think BBC BASIC is unique in this respect, but it is certainly very unusual for an interpreted BASIC to provide native support for 80-bit floats and it is something that I like to point to as a valuable feature.

Given what I have said above, it is irritating that Microsoft decided not to support 80-bit extended-precision floats in their compiler family. You can declare a variable to be of long double type, but in fact that is treated by the compiler as a synonym of double and the precision is no different. That can make it difficult or impossible to produce results which are as accurate as they theoretically could be. Even more surprisingly the ARM CPU family provides no access at all to 80-bit float values, even if they are used temporarily by the FPU (and I'm not sure whether that is the case or not). Unfortunately that means even GCC treats long double as a synonym of double when targeting ARM.

On the efficiency of word-extraction functions

A number of BASIC dialects provide a function which returns a single word from a string, selected according to its ordinal position. Typically the string is split either at a space character or at a specified delimiter. One such dialect is Liberty BASIC, in which the word$() function does this. However BBC BASIC has never supported this functionality, either natively or (in the case of BBC BASIC for Windows) in a library. This begs the question: "why not?".

It all comes down to efficiency. BBC BASIC, despite being a traditional interpreted language, has a reputation for relatively fast execution. Whilst in part this results from careful design of the interpreter (which is coded in assembly language) just as important is the choice of what functionality to provide. Consider this piece of Liberty BASIC code:

t$ = "The quick brown fox jumps over the lazy dog."
for i = 1 to 9
  print word$(t$, i)

This works fine, but when you think about exactly what is going on under the hood not everything in the garden is lovely. Each time round the loop (except the first) the word$() function has to repeat everything it did on every previous iteration!

So on the second time round, when it is finding the 2nd word in the string, it can only do that by first finding the first word. And on the third time round, it is having to do again everything it did on both the first and second iterations!

By the time it's got to the 9th time round it's had to find the 1st word 9 times, the 2nd word 8 times and the 3rd word 7 times (and so on). This is hopelessly inefficient: just imagine trying to extract every word in an 80,000-word novel this way.

It makes much more sense to split the string into its individual words in one operation, then there is no wasteful repetition. And that's what the function that BBC BASIC does provide (FN_split in the STRINGLIB library) is designed to do.

If for some reason you cannot live without the functionality of LB's word$() there is a way of improving its efficiency. The code listed below splits the entire string into its component parts on the first call, then on subsequent calls it checks whether the same string has been supplied. If it has it doesn't bother to repeat the splitting operation but just returns the word from the previously created array:

INSTALL @lib$+"stringlib"

t$ = "The quick brown fox jumps over the lazy dog."
FOR i% = 1 TO 9
  PRINT FNword$(t$, i%)

DEF FNword$(a$, n%)
PRIVATE a$(), p$, c%
IF p$<>a$ p$ = a$ : c% = FN_split(p$, " ", a$())
IF n%<1 OR n%>c% THEN = ""
= a$(n%-1) 

The price you pay for the improved speed is memory usage, because the array must be retained from one call to the next. What's more the array's memory is leaked each time the function is called with a string containing more words than the previous maximum.

Friday, September 16, 2016

It must sometimes seem that I only write a new blog post when I'm frustrated by some feature of Windows, and I'm sorry to say that's the case once again! It turns out that this is a longstanding issue, but it's one that has only been brought to my attention recently by a report of a surprising behaviour in LB Booster: pressing the Escape key causes the window to close unexpectedly, but only if it incorporates a TEXTBOX or TEXTEDITOR control which has the input focus. Superficially this is very peculiar.

I am grateful to Anatoly Sheyanov for having discovered the true cause, which is - to quote Raymond Chen of 'The Old New Thing' fame - "when you hit ESC in a multiline edit, it posts a WM_CLOSE to its parent in the mistaken belief that it is part of a dialog box.  This is for compatibility with Windows 2.0, which behaved this way.  It's annoying now, but compatibility means having to be bug-for-bug compatible with the previous version". This was written back in 1999 but appears to be still true today.

My frustration stems from the obvious fallacy that this bug needed to be preserved - and still does - "for compatibility with Windows 2.0". It would have been straightforward for Microsoft to introduce a new window style bit (or extended style bit) which, when set, disabled this rogue behaviour and instead caused the Edit Control to send the usual WM_COMMAND message containing the IDCANCEL code. Since applications written for Windows 2.0 shouldn't be setting this undefined bit they would carry in working as before, but new applications could set the bit and get the expected behaviour.

Another approach would have been to fix the bug in the Edit Control but to arrange that Windows applies a compatibility shim unless the program contains a manifest declaring that it isn't needed. This is the standard way that Windows addresses compatibility issues that might arise from the introduction of a new feature or changed behaviour of an existing feature. After all, back in the Windows XP days 'Version 6 Common Controls' were introduced, which were significantly different from their predecessors. To take advantage of them a program needed to declare compatibility in its manifest, so the 'Escape sending WM_CLOSE' bug could have been fixed at that stage.

Unfortunately there aren't any very straightforward workarounds for this bug. The only foolproof solution is to subclass the Edit Control and prevent the Escape keypress even reaching it, which is messy and may be impractical in some languages. The bug is an annoyance and an inconvenience which could have been entirely avoided as long ago as 1999, or before, had Microsoft only chosen to do so.

Sunday, May 19, 2013

Arguably, the most serious incompatibility between LB Booster and 'genuine' Liberty BASIC is the lack of support for huge strings. The maximum string length in LB4 isn't quoted anywhere, as far as I know, but is probably limited only by the memory available to BASIC, which is usually stated as being in the region of 70 Mbytes (although presumably one shouldn't expect it to work properly if a single string uses a significant proportion of that memory). In any case it is a lot bigger than BBC BASIC's 64 Kbytes (65535 characters) limit.

The ability to have multi-megabyte strings isn't necessarily desirable, because it can encourage the use of inappropriate algorithms. For example suppose one wants to count the number of lines in a text file. The traditional way, and the 'natural' way in a language which doesn't support huge strings, is to read the file sequentially, incrementing a counter for each line read. Only one line needs to be buffered in memory at a time, and the process is quite efficient.

In a language like Liberty BASIC, however, there is a temptation to read the entire file into a string - because you can - and then to scan the string for line delimiters (for example using the INSTR function) in order to count the lines. That will work, but it is highly inefficient of memory usage and CPU time. Firstly it involves holding the entire file in memory, which may be many megabytes, and secondly the INSTR function may need to scan the string from the beginning every time (or at least make a copy of the string first).

In a simple benchmark using LB 4.04, counting the lines in a 1 Megabyte text file with the first (sequential read) approach took about one second and with the second (whole file loaded into a string) approach took about 130 seconds. Repeating the test using LBB (for how that was possible, read on!) gave timings of 0.2 seconds and 20 seconds respectively. This illustrates the kind of speed improvement possible by using LBB, but in both cases loading the entire file into a string was about one hundred times slower than the sequential approach!

However, whilst it is possible to argue that supporting huge strings isn't always desirable, a significant proportion of LB programs do rely on that capability. To improve compatibility there is no alternative but for LB Booster to do the same. In investigating how that might be possible I first looked at the practicality of adapting the HUGESLIB library, which provides limited support for huge strings in BBC BASIC for Windows. Although in principle having the required functionality, it would involve identifying which string variables need to be able to hold huge strings (in itself non-trivial) and then substituting calls to library functions whenever those strings are manipulated.

I eventually decided that such an approach would be too complicated and too likely to suffer from obscure bugs. The only other possibility was to adapt BB4W itself to handle huge strings natively. Whilst clearly far from trivial, in fact such a modification wasn't desparately difficult for a couple of reasons. Firstly, I had already tackled increasing the maximum string length once before, when it was increased from 255 bytes (the limit in Acorn versions of BBC BASIC) to 65535 bytes, and the techniques used on that occasion are, in principle at least, fairly readily extended to support even longer strings. Secondly, because the 64K limit implied the string length being stored as a 16-bit quantity, the fact that the CPU's native registers are in fact 32-bits made it quite easy to adapt existing code (typically where the string length had previously been stored in the 16-bit CX register it could instead be stored in the 32-bit ECX register).

So it was that I modified the BB4W interpreter to support huge strings, specifically for the benefit of LBB. It's quite likely that the resulting performance is not as good as it might have been had huge strings been anticipated from the start, since in some cases the algorithms don't scale too well, but assuming that most strings will still be shorter than 64 Kbytes a typical program shouldn't experience much impairment. The version of LB Booster with this modification is, at the time of writing, in a beta test phase and is what was used to run the benchmark program.

Of course this raises a particular difficulty in respect of BB4W - should I make the 'huge string' version available to BBC BASIC programmers as well as to Liberty BASIC programmers? That is a much more tricky proposition, because unlike LBB - where the huge strings improve compatibility - the change from 16-bit to 32-bit lengths will inevitably impair compatibility and break some existing BBC BASIC programs. For example programs which assume the 'string descriptor' is 6 bytes long won't work when it increases to 8 bytes, and programs which include assembler code to manipulate strings almost certainly would need to be changed.

So this is quite a dilemma for which I haven't found a satisfactory resolution. I could simply not make the huge-string version available to BBC BASIC programmers at all, but that would seem rather unfair. Or I could upgrade BB4W and document the program modifications necessary (it's happened before, after all, when the strings were changed from 255 to 65535 characters). Or I could somehow make both versions available, but that greatly complicates version control, maintenance, automatic upgrades etc. There's no perfect answer!

Sunday, September 11, 2011

"If you can't beat them, join them" is what they say, and that's exactly what I've done in respect of Liberty BASIC! In an earlier blog post I compared BBC BASIC for Windows and Liberty BASIC, and explained my reasoning for believing BBC BASIC to be the better of the two. But that's not to say I can't see the attraction of LB to some people, particularly in having support for Windows GUI features as a standard part of the language rather than being provided in a library.

I've argued before, and still very much believe, that building in a rich set of GUI features as standard can result in a bloated language. This is especially true in the case of an interpreted language when every 'compiled' executable needs to include support for all those features, whether the user's program needs them or not. I've always suspected that this explains, at least in part, the huge size of Liberty BASIC executables (not far short of 3 Megabytes, however small the program).

But whilst the principle of providing GUI support by means of libraries (which is what BBC BASIC does) is sound, in practice there hasn't actually been support for the full range of facilities provided by Liberty BASIC, at least not in a straightforward way. Certainly there are BB4W libraries for the main Windows GUI elements, but LB goes somewhat further, for example you can change the colours of standard Windows controls (whether that's a good idea is arguable) and you can arrange that buttons are automatically relocated when a window is resized.

So I've recently remedied this by writing a BBC BASIC for Windows library LBLIB which makes available the full range of LB features to a BBC BASIC program. Indeed, it does so as far as possible in a way that is fully compatible with Liberty BASIC, and this has made possible a brand-new product: Liberty BASIC Booster!

But I'm getting ahead of myself in the story. Some while ago I wrote an automated translator from QBASIC (or Quick Basic) to BBC BASIC - QB2BBC. Unlike many translators this attempts to perform a 'perfect' translation that requires no user tweaking to achieve identical functionality to the original. The down-side of producing such an accurate translation is that the code it generates is often quite unlike what a human would write, and it doesn't give a good indication of what well-written BBC BASIC code looks like.

At the heart of QB2BBC is a parsing engine which breaks down the QBASIC program to its fundamental elements and then constructs the BBC BASIC program from them. It occurred to me some time ago that this parsing engine could be adapted quite easily to translate other languages into BBC BASIC, one obvious candidate being Liberty BASIC. So earlier this year I started to look quite seriously at the possibility of writing a Liberty BASIC to BBC BASIC translator (tentatively to be called LB2BBC).

But of course there was a big problem. With QBASIC originating from the 1980s, in the era of CP/M and MS-DOS, pretty much every feature it provides has a direct or near equivalent in BBC BASIC. Whilst not always straightforward, the task of QB2BBC was primarily one of translation rather than emulation (the only major exception being QBASIC's music capabilities, which are emulated at run-time by the QBLIB library). With Liberty BASIC however, translating the language syntax to BBC BASIC was only a small part of the challenge; it left the GUI facilties (principally windows, controls, graphics and sprites) completely unsupported.

This is where we complete the circle. By combining the translation capabilities of LB2BBC with the emulation capabilities of LBLIB it becomes possible to run most Liberty BASIC programs, without actually needing Liberty BASIC itself! In consultation with some leading Liberty BASIC advocates it became clear that there might be a market for this, not as as translator to BBC BASIC but as a 'Liberty BASIC Booster'. To the user it would appear as a way to speed up LB programs (up to ten times in some cases) and to create compact single-file executables, without it being obviously apparant that BBC BASIC was at work 'under the hood'.

The compatibility of LBB with LB isn't perfect. As I noted at the end of my article comparing the two BASICs there are two areas in which LB provides a capabilility that BBC BASIC doesn't: support for huge strings and arbitrary-precision integer arithmetic. Therefore programs relying on either of these features cannot run under LBB.

Some may find it superficially strange that I should be supporting Liberty BASIC in this way. One reason is that whilst LBB doesn't directly benefit BBC BASIC, neither does it significantly damage it: I wouldn't expect that any users of LBB might have been persuaded to convert to BB4W instead. Secondly, LBB demonstrates the amazing power and flexibility of BBC BASIC for Windows; with how many other high-level programming languages could it have been achieved? But mostly it's been a fascinating technical challenge, pushing my programming skills to the limit.

Thursday, July 22, 2010

On the same topic as last time, there's another good example of how assembling code at run-time can provide a worthwhile advantage. The x86 processor's division instructions are particularly slow, even on the newest CPUs, and it's common for modern compilers to convert division by a constant to a multiplication followed by a shift. If the multiplicand (which is effectively the reciprocal of the divisor, multiplied by a power of two) and the shift count are chosen carefully - and in some cases a final adjustment made - the result is identical to the division instruction but the speed is much faster.

The rub, of course, is that this technique is normally only applicable to division by a constant which is known at compile time. If you don't know what value you want to divide by until run-time you've got to use a conventional division instruction (strictly speaking if you know the divisor is one of a set of predetermined values you could select from a matching set of routines, or look up the multiplicand and shift count from a pair of tables, but that could eat up most if not all the speed advantage).

There's no such limitation in the case of BBC BASIC. Because the code is assembled at run-time the multiplication-plus-shift trick can be used for any divisor, so long as it remains unchanged for that particular run. For example you might want to divide by the screen width, a value which is constant at run-time but usually not known at compile time. The application would need to contain code for calculating the multiplicand and shift count from the divisor, but that is used only once during the initialisation phase of the program (in practice one would probably use an 'assembler macro' to do it).

Wednesday, December 30, 2009

BBC BASIC allows you to incorporate assembly language code in your BASIC program, typically for use when interpreted BASIC isn't fast enough or for specialised purposes such as coding interrupt service routines. Using a hybrid of BASIC and assembler code is a powerful technique, allowing you to use BASIC for the bulk of the program (typically including the user interface) and assembler for the speed-critical parts (which are likely to be a relatively small proportion of the whole).

Needless to say the assembler provided in BBC BASIC is specific to the particular processor on which it runs. So the original BBC Micro BASIC incorporates a 6502 assembler, Acorn's BASIC for RISC OS machines incorporates an ARM assembler, BBC BASIC (Z80) (e.g. for CP/M or on the Z88) incorporates a Z80 assembler and BBC BASIC (86) for MS-DOS incorporates a 16-bit x86 assembler. BBC BASIC for Windows incorporates a full 32-bit x86 (IA-32) assembler, including support for floating point and MMX instructions.

Whilst support for 'inline' assembly language code is not unusual in programming languages (for example it's a standard feature of C), BBC BASIC provides it in a unique way. Conventionally, any assembler code included in a program is converted to machine code (i.e. assembled) at 'compile' time and incorporated in the final executable as binary data. In contrast, BBC BASIC incorporates the assembler 'source' code in the executable (usually in a compressed format) and assembles it to machine code when the program is run.

Let that sink in for a moment. If the source code is assembled at run-time, it means the BBC BASIC executable must itself contain an assembler - which indeed it does (albeit a small and very fast one). As far as I know no other programming language creates executables which contain an assembler, let alone a full IA-32 assembler.

In many cases this very different way of dealing with embedded assembler code won't have any practical consequences - the end result will be equivalent to the more conventional method. However it makes possible some things which would otherwise be very difficult or messy to achieve. In particular it allows the assembled machine code to vary according to some condition which is determined at run-time.

Why might that be valuable? Suppose, for example, that the assembler code accesses one or more memory locations, which means that the addresses of those locations must be known. Typically, those addresses will vary from one run of the program to the next, or between one PC and another, so they aren't known when the executable is created (i.e. when the program is 'compiled'). Conventionally this means that the addresses can't be incorporated as 'constants' within the assembler code, instead they must be passed to the code as parameters (e.g. on the stack) when it is run.

However in the case of BBC BASIC things are very different. The assembler source code is converted to machine code at run time, so it can usually be arranged that the addresses are known by then. As a result, the 'variable' memory addresses (which change from one run to the next) can be incorporated in the assembled machine code as 'constants', making the code both simpler and faster.

To take a practical example, suppose the assembler code needs to load the eax register from a memory address that is known only at run-time. In a conventional programming language the assembler source code will look something like this (where the address is passed to the assembler code on the stack):

mov ebp,esp ; get pointer to stack frame
mov ebx,[ebp+offset] ; get address
mov eax,[ebx] ; load eax from memory

But in the case of BBC BASIC the code can simply be as follows, because the address is already known:

mov eax,[address] ; load eax from memory

If there are many such memory references the impact on execution speed can be considerable. Similar considerations may apply whenever the code can be simplified by incorporating values as 'immediate constants' rather than 'variables'.

There's another valuable benefit of BBC BASIC assembling source code at run-time. In Microsoft Windows different processes run in separate (virtual) address spaces and are effectively quite well isolated from each other (one process cannot see another process's memory directly). However it is possible for one process to 'inject' code into another process and then run it there. The snag is that the address in the remote process at which the code must be loaded, and executed, isn't known until run-time.

This poses quite a problem for a conventional language, as IA-32 machine code isn't (in general) 'position independent' and so must be assembled (and linked, if appropriate) to run at a specific address. Typically the assembler code has to be written in such a way that it can be 'relocated' at run time - by 'patching' it using, for example, C code - according to the address at which it will eventually be loaded in the remote process. This is potentially very messy, prone to error and difficult to debug.

With BBC BASIC this is all very much easier. Because, by the time the code is assembled, the address at which it must eventually run is known, there is no requirement for it to be 'patched' or 'relocated' (the BBC BASIC assembler has a specific feature whereby the code can be assembled so that it will run at an address different from that at which it is initially stored). This makes it exceptionally well-suited to injecting code into another process.

Saturday, November 08, 2008

There's little doubt that the main competitor to 'BBC BASIC for Windows' is Carl Gundel's 'Liberty Basic'. Superficially the two products have a lot in common:

* They are both 'Windows only'.
* Their IDEs have very similar interfaces and capabilities.
* Both provide direct access to the Windows API and other DLLs.
* Both are interpreters (neither compiles to native code), in particular this allows them to support an EVAL function.
* Both use a 'run-time engine' to execute a tokenised version of the user's BASIC program.
* Both allow BASIC programs either to be executed directly from the IDE, or to be converted to a self-contained executable.

I have even been described in one blog as "a sort of British Carl Gundel"!

However when one looks under the surface there are in fact major differences between the two BASICs. Perhaps the most important is their contrasting approaches to providing capabilities beyond those of 'standard' (i.e. traditional) BASICs. Such capabilities include support for Windows GUI components (menus, dialogue boxes and so on), sorting of data arrays, sprite commands etc.

Liberty Basic builds these capabilities into the language itself. It therefore needs significantly more keywords than, and is more complex than, BBC BASIC. By contrast 'BBC BASIC for Windows' is a 'lean and mean' language: the interpreter provides only the core set of BASIC language features. Support for capabilities such as those mentioned above is provided by means of libraries (surprisingly, Liberty Basic doesn't support code libraries at all).

In this respect you can say that BBC BASIC has a lot in common with the C language, which also relies greatly on libraries (there are other ways in which BBC BASIC has similarities to C, which I will touch on later).

Perhaps the most striking consequence of this fundamental difference between the BASICs is in the size of their 'compiled' executables. The 'BBC BASIC for Windows' run-time engine is tiny (less than 64 kBytes) and its standalone executables - consisting of a single EXE file - are often less than 100 kBytes in size. Liberty Basic's executables, on the other hand, are never smaller than about 2.7 Mbytes (uncompressed) and consist of around ten separate files.

Carl Gundel, perhaps not surprisingly, defends the Liberty Basic executables on the grounds that modern PCs have so much memory and so much disk space that even 3 Mbytes isn't "large". However, compact executables really can have significant benefits, even on such systems.

For a start a small interpreter will tend to run more quickly, because it makes more efficient use of the CPU's instruction cache. Indeed BB4W's interpreter is so small that it will fit in its entirety within the instruction cache of some modern processors (e.g. the 64K cache of the AMD Athlon 64). This contributes to the marked speed difference between BBC BASIC and Liberty Basic (using a Sieve of Eratosthenes benchmark 'BBC BASIC for Windows' took 1.1 seconds and Liberty Basic took 16.6 seconds: fifteen times slower!).

The other big advantage of compact executables is speed of download via an internet connection. BBC BASIC's small, single-file EXEs can be placed on a web site and, with a couple of clicks of the mouse, can be running on the user's PC within a fraction of a second. There's no need to download them (manually) to the PC, nor to decide where to store them; Windows does it all behind the scenes.

I mentioned earlier that BBC BASIC has other similarities to C. These include its ability to access memory directly, at an arbitrary address, and the incorporation of an 'inline' assembler. Of course these are 'advanced' features, and most users will neither need nor want to utilise them, but in the hands of an expert they make it possible for BBC BASIC for Windows to do things that Liberty Basic could never do on its own.

An example is accessing 'object-based' APIs such as Direct3D, COM automation (ActiveX) etc. BBC BASIC can manage this quite easily, but Liberty Basic needs to rely on external DLLs (typically written in C or Visual Basic) to achieve it. Even things as simple as accessing an API function exported by ordinal rather than name are beyond Liberty Basic's capabilities.

Although BBC BASIC for Windows is much faster than Liberty Basic, there can still be occasions when it is not fast enough. This is where the built-in assembler can be invaluable; programs can be fairly easily written in which the few time-critical parts are written in assembler and the rest in BASIC, a hybrid approach which is extremely powerful and flexible.

To be fair, there are a couple of respects in which BBC BASIC is less capable than Liberty Basic: these are the maximum sizes of integer and string variables. In common with most modern languages BBC BASIC uses 32-bit integers whereas Liberty Basic supports 'arbitrary precision' integer arithmetic. BBC BASIC's strings are limited to 65535 characters, whereas Liberty Basic's strings can be much longer. In those very rare circumstances when these are important there are workarounds for both issues in BBC BASIC.

In conclusion I am quite convinced that BBC BASIC for Windows is a better language than Liberty Basic. It creates smaller, faster executables. It allows you to do far more things without recourse to using an external DLL. BBC BASIC is a real enthusiasts' language; whatever you want to do it will rise to the challenge.