Files
five/docs/five-readability-en.md
Charles KWON OhJun 7c61db70c3 fix: Critical code review fixes — race conditions, panic recovery, LTRIM/RTRIM
CRITICAL fixes:
- fileio.go: Add sync.Mutex to file handle table (race condition #2)
  allocHandle/getHandle/removeHandle thread-safe helpers
- goroutine.go: Add defer/recover to GoLaunch/GoLaunchBlock
  Goroutine panic no longer crashes entire process (#5)

HIGH fixes:
- strings.go: Implement proper LTrim (TrimLeft) and RTrim (TrimRight)
  Previously both aliased to AllTrim — silent semantic bug (#18)
- register.go: TRIM = RTrim (Harbour compatible)

From 53-issue senior code review.
Remaining: 47 issues (HIGH: 10, MEDIUM: 18, LOW: 16, CRITICAL: 3)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 10:17:30 +09:00

6.3 KiB

Five's Readability — The Real Advantage in the AI Era

Why Readability Matters When AI Writes Code

AI generates code automatically now. But there's a problem:

  1. AI creates complex code — it works, but humans can't understand it
  2. Unmaintainable without AI — if the AI service goes down, code becomes a black box
  3. Bugs hide in complexity — if you can't read it, you can't debug it
  4. Team collaboration breaks — nobody except the AI understands the code

Five solves this fundamentally.

Same Task, Different Readability

Query Customer List

// Five (PRG) — 8 lines
USE customers NEW
SET FILTER TO balance > 10000
GO TOP
DO WHILE !Eof()
   ? name, city, balance
   SKIP
ENDDO
// Go — 27 lines
func listCustomers() {
    db, err := sql.Open("sqlite3", "customers.db")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()
    rows, err := db.Query(
        "SELECT name, city, balance FROM customers WHERE balance > $1",
        10000,
    )
    if err != nil {
        log.Fatal(err)
    }
    defer rows.Close()
    for rows.Next() {
        var name, city string
        var balance float64
        if err := rows.Scan(&name, &city, &balance); err != nil {
            log.Fatal(err)
        }
        fmt.Println(name, city, balance)
    }
    if err := rows.Err(); err != nil {
        log.Fatal(err)
    }
}
Language Lines Error handling Non-developer readable
Five (PRG) 8 Built-in Yes
Python 12 Manual Maybe
Go 27 Required No
Java 15 Required No

Why PRG is Easy to Read

1. Reads like English sentences

USE customers NEW                    // Open customer file
GO TOP                               // Go to the first record
DO WHILE !Eof()                      // Repeat until end of file
   IF balance > 10000                // If balance exceeds 10000
      ? name, balance                // Print name and balance
   ENDIF                             // End condition
   SKIP                              // Move to next record
ENDDO                                // End loop

Even non-programmers can follow the flow. No {, }, func, defer, or cryptic symbols.

2. Everything is explicit

// Five — endings are clear
IF condition
   ...
ENDIF                // IF ends here

FOR i := 1 TO 10
   ...
NEXT                 // FOR ends here

DO WHILE condition
   ...
ENDDO                // WHILE ends here
// Go — count the braces
if condition {
    for i := 0; i < 10; i++ {
        if another {
            // ...
        }     // ← which one does this close?
    }         // ← this one?
}             // ← or this one?

3. Variable names tell their type

LOCAL cCustomerName, nTotalBalance, dLastPurchase, lIsActive

cCustomerName := "Charles KWON"       // c = Character
nTotalBalance := 15000.50             // n = Numeric
dLastPurchase := Date()               // d = Date
lIsActive := .T.                      // l = Logical

Hungarian notation makes types visible in names:

  • c = Character (string)
  • n = Numeric (number)
  • d = Date
  • l = Logical (boolean)
  • a = Array
  • o = Object

Even AI-generated code is self-documenting with these prefixes.

4. DEFER keeps it safe AND clean

// Go — defer exists but err checks pollute the code
db, err := sql.Open("sqlite3", dsn)
if err != nil {
    return fmt.Errorf("open failed: %w", err)
}
defer db.Close()
result, err := db.Query("SELECT ...")
if err != nil {
    return fmt.Errorf("query failed: %w", err)
}
defer result.Close()
// Five — DEFER + clean business logic
db := sql.Open("sqlite", dsn)
DEFER db:Close()                     // Same as Go's defer!

result := SqlScan(db, "SELECT ...")
// Errors handled in one place via BEGIN SEQUENCE
// But the code stays readable

Five brings Go's defer as DEFER — same safety, same guarantee. The good parts of Go, without the if err != nil noise.

AI-Era Scenarios

Scenario 1: AI service goes down

Go/Python/Java project:

  • 100K lines — days to understand structure
  • Complex type systems, generics, interfaces
  • Framework dependencies to untangle
  • New developer needs weeks to onboard

Five project:

  • Same features in 30K lines — less code to read
  • USE, SKIP, SEEK — commands mean what they say
  • Inexperienced developer can read code in one day

Scenario 2: Emergency bug fix

// Assume the bug is here
USE orders NEW
SET FILTER TO date >= Date() - 30
GO TOP
DO WHILE !Eof()
   IF amount > 0
      nTotal += amount         // ← bug here: should be = instead of +=?
   ENDIF
   SKIP
ENDDO

Non-developers (sales team, managers) can read this and understand "nTotal is accumulating something." This level of comprehension is impossible with Go code.

Scenario 3: Verifying AI-generated code

// AI-generated Five code — humans can verify
FUNCTION CalcDiscount(nPrice, nQuantity)
   LOCAL nDiscount
   IF nQuantity >= 100
      nDiscount := nPrice * 0.15      // 100+ units: 15% discount
   ELSEIF nQuantity >= 50
      nDiscount := nPrice * 0.10      // 50+ units: 10% discount
   ELSE
      nDiscount := 0                   // No discount
   ENDIF
   RETURN nDiscount

A business stakeholder can look at this code and ask: "Is 15% for 100+ units correct?" — try doing that with Go generics.

Five + Go = The Optimal Combination

Simplicity alone isn't enough. Simple code with powerful capabilities — that's the goal.

IMPORT "database/sql"
IMPORT _ "modernc.org/sqlite"

PROCEDURE Main()
   LOCAL db, aRows, i

   db := sql.Open("sqlite", ":memory:")
   DEFER db:Close()

   db:Exec("CREATE TABLE orders (id INTEGER, amount REAL)")
   db:Exec("INSERT INTO orders VALUES (1, 15000)")

   aRows := SqlScan(db, "SELECT * FROM orders")
   FOR i := 1 TO Len(aRows)
      ? aRows[i]["id"], aRows[i]["amount"]
   NEXT

   RETURN

SQL database access in PRG syntax. Go's database/sql powers it behind the scenes, but the person reading this code doesn't need to know Go.

The Bottom Line

In an era where AI writes code, code that humans can read is the real asset. Five is the only systems language where AI-generated code can be verified by humans — even non-developers.