# 13. Differences from BASIC 7.0

If you already write Commodore BASIC, this is the chapter to read first. Everything
here is deliberate, and everything is recorded in the repository's `TODO.md` with the
reasoning — this is the short version.

## The language

### Variables carry a type suffix, and the suffixes differ

| | Integer | Float | String |
|---|---|---|---|
| C128 | `A%` | `A` | `A$` |
| akbasic | `A#` | `A%` | `A$` |

There is **no such thing as an unsuffixed variable**. A bare name is a label.

### `=` works in a condition, and `==` works everywhere

`IF A = 5 THEN` does what you expect. `==` also means equality and is what the older
programs in this repository use. Outside a condition `=` is assignment, as always.

### `AND`, `OR` and `NOT` in conditions

These work, and a condition is a whole expression rather than a single comparison, so
`IF A = 1 AND B = 2 THEN` parses. Truth is nonzero, so `IF A THEN` works too.

### `MID` and `INSTR` count from zero

A C128 counts from one. A failed `INSTR` gives -1 rather than 0.

### `THEN` needs a verb

`IF X THEN 100` is not a jump. Write `IF X THEN GOTO 100`.

### Strings are 255 characters and cannot contain a quote

There is no escape character.

### Numbers

Integers are 64-bit and floats are IEEE doubles, so `PRINT 1.5` gives `1.500000`. A
leading zero is not octal; `0x` is hexadecimal.

### Mixed arithmetic follows the left operand, not the wider type

**A C128 promotes to float. This does not.** An integer on the left converts the right
operand to an integer and throws its fraction away, so `A# * 0.45` is `0` where
`0.45 * A#` is `1.35`. It is consistent, it is inherited from the Go interpreter this was
ported from, and **nothing fails when you get it wrong** — the program computes something
else and carries on.

[Chapter 3](03-the-language.md#the-left-operand-decides-whether-the-arithmetic-is-integer-or-float)
has the two rules that keep you out of it. This is the difference from 7.0 most likely to
turn a working listing into a quietly wrong one.

### Structures are an addition

BASIC 7.0 has no records at all. `TYPE`/`END TYPE`, `DIM X@ AS T`, the `@` suffix, `.` and
`->`, `PTR TO` and `POINT ... AT` are all new here, and **[Chapter 16](16-structures.md)**
is the whole of it. Nothing about it changes an existing program.

Two consequences a C128 programmer should know. A structure assignment **copies**, like
every other assignment; sharing is spelled `POINT`. And a type name is a bare word, so it
shares a namespace with verbs and labels — `TYPE POINT` is refused because `POINT` is now a
verb.

## Block structure

**A whole loop on one line does not loop.**

```basic
10 FOR I# = 1 TO 3 : PRINT I# : NEXT I#
20 PRINT "DONE"
```

```output
DONE
```

The loop prints nothing. Block skipping walks source *lines*, so a `NEXT` on the same line as
its `FOR` is never reached. The same applies to `DO`/`LOOP`. Write loops across lines.

## Two known defects in `FOR`

Both are recorded, both have tests asserting the correct behaviour, and both are
waiting on a decision rather than on work:

- **A step that overshoots runs the body one extra time.** `FOR I = 1 TO 9 STEP 3` runs
  with 1, 4, 7 *and 10*.
- **`FOR I = 1 TO 1` does not run its body at all**, where every other BASIC runs it
  once.

The two errors cancel out for a step of 1, which is why they went unnoticed. Fixing
them would change the output of a checked-in acceptance file, which is not something
this project does silently.

**A loop counter does not survive its loop.** It lives in the loop's own scope, so
reading it afterwards gives zero.

## Direct mode

A statement typed with no line number runs immediately, as it should. This was not
true until recently — the interpreter used to file everything but a handful of verbs as
program text.

## Line numbers

**A program in a file does not need them.** Every BASIC this dialect descends from
required a number on every line; here that requirement belongs to the prompt alone,
where the number is the only thing separating program text from a statement to run now.
A program loaded from a file, or handed to the library as a string, may leave them out,
and a line without one is given the next number going. The two mix: a numbered line sets
where the next unnumbered one goes.

This is QuickBASIC's idea rather than the C128's, and it is here for the same reason
QuickBASIC had it — a program that branches by `LABEL` never names a line number, so the
numbers are maintenance with nothing on the other end of it.

Two consequences worth knowing:

- **`GOTO <number>` must name a number the program wrote.** In a file with no line
  numbers `GOTO 100` would otherwise find the hundredth line and branch there. It is
  refused before the program runs. `GOTO <label>` is unaffected.
- **`LIST` and `DSAVE` show the numbers that were handed out**, one apart. `RENUMBER`
  before `DSAVE` if you want gaps to insert into.

An unnumbered program is capped at 9998 lines, which is the cap that already applied.

## Errors

`ER` and `EL` are **`ER#` and `EL#`**, ordinary global variables. `ER#` holds this
interpreter's error code, which bears no relation to a Commodore error number. Print
`ERR(ER#)` for the text, and see [Chapter 15](15-error-codes.md) for the whole list.

## Graphics

- **A coordinate is a window pixel, not one of 320 by 200.** A C128 listing therefore
  draws in the top-left corner of a larger window; `SCALE 1, 319, 199` gives it the
  whole window back. `RGR(1)` and `RGR(2)` report the size, and are ours rather than
  7.0's — where 7.0's `RGR` takes only field 0, the `GRAPHIC` mode.
- **`SSHAPE` puts a handle in the string, not the pixels.** You can pass it to `GSHAPE`
  and `SPRSAV`; you cannot save it or take its `LEN`.
- **`WIDTH` is emulated** by drawing parallel passes.
- **Drawing persists, and the text layer covers it.** A drawing goes into a layer that
  survives the frame, so a program draws its picture once and it stays — no redrawing, no
  capturing it into a sprite. What is still true is that the text layer repaints every row
  it owns, opaque, every frame, and by default it owns the whole window. `WINDOW` shrinks
  it and hands the rest over. The two together are what makes a picture usable:
  `WINDOW 0, 0, 39, 1` keeps a one-row status line and gives the drawing verbs everything
  below it.
- **A drawing still has to fit in one batch.** The host runs a fixed number of source lines
  and then presents, and an `SSHAPE` capture spanning that boundary comes back **half
  drawn** — the part issued since the present, over whatever was there before. Measured
  against the standalone frontend's 256 lines a batch: after synchronising to a jiffy edge,
  220 lines of drawing survive a capture and 250 do not. This bites a *capture*, not the
  drawing itself, so it matters far less than it did when capturing was the only way to
  keep a picture. The only way a program can see the boundary is to watch `TI#`, which is
  refreshed once per batch.
- **`CHAR` ignores its colour argument** and needs a text device with a cursor.

## Sound

- **`PLAY` and `SOUND` do not block.** The statement after them runs immediately.
- **`FILTER` is refused.** There is no filter stage to configure.
- **`PLAY`'s `M` is accepted and does nothing.**
- **`TEMPO`'s calibration is a choice**, not a transcription.

## Sprites

- **Coordinates are window pixels**, not the VIC-II's raster space, and `SCALE` does
  not apply to them.
- **`SPRSAV` takes an integer array**, not a string, for the data form — a string here
  cannot hold a zero byte. It also takes an **image file path**, which a C128 cannot.
- **A sprite loaded from a file keeps the image's own size**, not 24 by 21.
- **`MOVSPR`'s speed unit is a choice.** The manual does not say what a unit is worth.
- **Collision is by shape**, not by pixel. A sprite nobody has shaped collides with its
  whole frame, expansion bits included, which is what a bounding box means here; `SPRHIT`
  narrows that to a box, a circle or a capsule. None of them is pixel-exact.
- **`SPRHIT` and `RSPHIT` are an addition.** BASIC 7.0 has `COLLISION` and `BUMP` and
  nothing else, and nothing about them changes an existing program.
- **Collision types 1 and 2 exist.** Type 2 means the rectangles `SOLID` registered, not a
  screen read back — a C128 collides a sprite against the bitmap's set pixels and this
  cannot, so the question is asked against geometry instead. Type 3 is still refused;
  there is no light pen.
- **`SOLID` is an addition.** BASIC 7.0 has no static collision geometry at all, and it is
  what lets a program collide with something that is not one of the eight sprites.
- **`RCOLLISION` is an addition, and nothing is resolved.** A contact is a *report*: it says
  what was hit, which way is out and how far, and reversing the ball is still the program's
  job. BASIC 7.0 has `BUMP` and a bitmask, and no way to ask any of this.
- **Priority and multicolour are recorded but not drawn.**
- **`SPRDEF` is out of scope.**

## Files

- **`PRINT #` and `INPUT #` need a space before the `#`.** `PRINT#1` scans as a
  variable name.
- **`RECORD` counts lines**, not fixed-length records.
- **`BLOAD` requires a length.**
- **`HEADER`, `COLLECT`, `BACKUP` and `BOOT` are refused.** They operate on a physical
  disk.
- **`DIRECTORY` is refused** because it is not written yet. The standard-library
  wrapper it was waiting on has landed, so the remaining work is the verb.

## Machine

- **`SYS` is refused.** There is no 6502 and no ROM.
- **`FETCH` and `STASH` are the same byte copy.** There is no expansion RAM to tell
  them apart.
- **`POKE`, `PEEK` and `POINTER` use real process addresses.** A wrong one is a
  segmentation fault, not an error message.
- **`BANK`, `FAST` and `MONITOR` do not exist.**

## Formatting

- **`PRINT USING` renders one field per statement.** `PRINT USING "### ###"; A, B` is
  not supported.
- **Exponential fields (`^^^^`) are not implemented.**

## Console

- **`SLEEP` and `WAIT` hold the program without blocking the host.** `SLEEP` with no
  host clock does nothing at all rather than waiting forever.
- **`TI` and `TI$` are `TI#` and `TI$`**, refreshed once per step.
- **`WAIT` polls ordinary process memory.** Nothing changes it but the host.
- **`KEY` stores macros and nothing expands them.**

## Limits

| | |
|---|---|
| Source lines | 9999 |
| Line length | 255 |
| String length | 255 |
| Variables | 128 |
| Array elements | 1024 per array, 4096 across every array and structure |
| Scopes | 32 |
| Labels | 64 |
| `DATA` items | 512 |
| File channels | 10 |
| Operations per line | roughly 16 |

Every one is a fixed pool. Nothing in the interpreter calls `malloc`, which is what
makes it safe to embed in a game that cannot afford a surprise allocation.

**A scalar does not come out of the 4096.** It lives in the variable itself, so creating
one inside a `GOSUB` or a `FOR` — including the loop counter — costs nothing and can be
done for as long as the program runs. An *array* declared inside a scope does come out of
it and is not given back: the pool never frees, which is what lets a pointer into a
record outlive the scope that declared it. In practice that means `DIM` at the top rather
than in a loop, which is where you would have put it anyway.
