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>
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:
- AI creates complex code — it works, but humans can't understand it
- Unmaintainable without AI — if the AI service goes down, code becomes a black box
- Bugs hide in complexity — if you can't read it, you can't debug it
- 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= Datel= Logical (boolean)a= Arrayo= 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.