13

On Commodore machines featuring CBM BASIC v2, the FRE() function to query the amount of memory available to BASIC returns a negative number when the result exceeds 32767 bytes:

Screenshot of a Commodore 64 where PRINT FRE(0) has been entered in direct mode, with the computer returning the value -26627.

This quirk does not exist on machines with CBM BASIC v4, v3.5, or v7.

I already understand, on a purely technical level, why a negative value is returned: the free memory is calculated as an unsigned 16-bit integer, but the FRE() routine interprets the result of this calculation as a signed 16-bit integer (which it goes on to convert to floating point). My question is whether this behaviour is by design or a bug. I don't recall any contemporary programming guides claiming it is a bug, and Commodore's own documenation doesn't refer to it as such. (The Commodore 64 User Guide, for example, simply says, "Note that FRE(X) will read out n negative numbers [sic] if the number of unused bytes is over 32K."

If this behaviour is by design, what benefit does it bring? Was it simply more expedient for the CBM BASIC interpreter programmers to have implemented it that way, or did they have some benefit for the end user in mind?

12
  • 3
    I'd say it's clearly a bug. A Commodore CBM BASIC v2 computer can't have a negative quantity of physical memory free because it can't fill more than it has. There's no benefit in a negative quantity so it's an unintended failure to deliver the behaviour a programmer would reasonably expect and require from FRE. Not aware anyone's written one before/since that returns a negative value. From what I've read Commodore life in those days, I'm sure the poor space-constrained and very time-constrained programmers didn't do it deliberately and wouldn't have let it go unfixed if they'd have a choice.
    – TonyM
    Dec 16, 2022 at 20:44
  • @TonyM: Prior to the Commodore 64, none of Commodore's machines would have had more than 31,744 bytes of user RAM available, and Commodore 64 BASIC was an exceptionally minor tweak to the previous CBM BASIC (mainly moving the portion in the range $C000-$DFFC to the range $A000-$BFFC for some reason, and shifting the parts above that upward three bytes, to allow space in the $E000-and-up portion for the three bytes that had been at $BFFD, but got replaced by a JMP).
    – supercat
    Dec 16, 2022 at 22:27
  • @supercat, sure but that doesn't change anything. Commodore built a new BASIC ROM by pulling in existing software without ironing out the bugs in the resulting new system, which left the FRE(0) bug. May well have been from insufficient testing of the new system or it may have been known and not acted on. A bad on the Commodore company for lack of testing but full sympathy to the programmers etc, for reasons said before.
    – TonyM
    Dec 16, 2022 at 22:53
  • 1
    It's interesting that the header prints correctly 38911 Bytes Free
    – PMF
    Dec 18, 2022 at 15:08
  • 1
    I do appreciate your line of reasoning, @paxdiablo :-) But documenting behaviour, as if it was intended or whatever, doesn't stop it being a bug. The documenter may wish it did but it won't because the documentation isn't blindly obeyed by the reader, but interpreted using knowledge of existing work and their collective/individual opinions. More simply, if doc has real rubbish, they'll recognise that and use their own definitions en masse, they won't reclassify at its command. Here, counting byte total as negative is still be a bug. That doc's not in control, it's subservient to conventions.
    – TonyM
    Dec 19, 2022 at 11:34

2 Answers 2

12

Whether that's a bug or just sloppy programming is hard to decide.

Maybe the designers needed to save some ROM space and simply decided that the main use case for FRE(0) i.e., you want to know how much memory is left, is when memory becomes tighter than 32k, which happens quickly even with smaller programs (so, "when you really need FRE(0), it will work"). On the other hand, it's pretty straightforward to convert the value into an unsigned integer, even from BASIC.

While initially it obviously is not working correctly and might be called a bug, over time it has transformed into an "accepted quirk".

3
  • From the point of the original programmers this worked correctly because that BASIC version was used in the VIC-20 before and it is an adaption from the BASIC in the PET computers where BASIC never had more than 32K RAM to work with. The question is more if it was deliberately or an oversight to not change that function when that interpreter was used in the C64 that had more that 32 K RAM for BASIC programs available.
    – BlackJack
    Dec 17, 2022 at 22:29
  • "Whether that's a bug or just sloppy programming" - most bugs are due to sloppy programming so I'm not sure of the mutual exclusion :-)
    – paxdiablo
    Dec 18, 2022 at 23:33
  • @paxdiablo Oh, well. You can program as "un-sloppy" as you want and will still produce bugs. Yes, there's definitely a difference.
    – tofro
    Dec 19, 2022 at 7:16
7

I already understand, on a purely technical level, why a negative value is returned: the free memory is calculated as an unsigned 16-bit integer, but the FRE() routine interprets the result of this calculation as a signed 16-bit integer (which it goes on to convert to floating point).

Exactly. That's the way it operates.

My question is whether this behaviour is by design or a bug.

That might be up to interpretation. I might go with neither.

  • It's not a bug, as the result is, as you know, a 16 bit unsigned integer.
  • But, as you as well mention, all return value in (MS-)BASIC are float
  • But (MS-)BASIC does not know unsigned integer, only signed.
  • Thus, all conversion from integer views a given 16 bit value as signed
  • Which results in all values above 32768 being converted into their negative counterpart

So while one can argue it's by design, as the language's function result handling is designed that way, I would rather classify it as accepted side effect.

(The Commodore 64 User Guide, for example, simply says, "Note that FRE(X) will read out n negative numbers [sic] if the number of unused bytes is over 32K."

Which supports that they simply did go along with that side effect.

If this behaviour is by design, what benefit does it bring?

Was it simply more expedient for the CBM BASIC interpreter programmers to have implemented it that way, or did they have some benefit for the end user in mind?

  • No need for a special handling in conversion.
  • No need for a function to do unsigned integer

and last:

  • Consistency.

I wouldn't go that far to say they thought about it in an explicit way - MS BASIC development at that point was simply chaotic and Special-to-Type - but not adding a special conversion kept the value within the range of further processing.

This is especially important when comparing with other values originally thought to be integer, as in float -1 is not equal 65535, while in integer it is.

1
  • I suspect that MS-BASIC was probably designed at a time when implementations were not expected to have more than 32768 bytes available for user programs, and the companies that licensed adaptations of it saw no need to add a customization to adjust the result of FRE(), even though variations of MS-BASIC included customizations for other integer-related issues (e.g. Applesoft accepts values -65535 to +65535 for PEEK and POKE, but Commodore BASIC does not; Applesoft's AND and OR operators coerce operands to 0 or 1 in a manner akin to C's && and || operators, while CBM BASIC does not; etc.
    – supercat
    Dec 16, 2022 at 21:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .