Files
five/docs/five-syntax-en.md
Charles KWON OhJun c0f175883c docs: Add math section to syntax reference + improve example comments
- five-syntax-en/ko: Add Math comparison table (Harbour RTL vs Go math)
- go_math_compare.prg: Detailed English comments explaining each section
- Example lists updated with go_math_compare.prg

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 11:31:44 +09:00

12 KiB

Five Language Syntax Reference

Five = 100% Harbour compatible + Go extended syntax. Existing PRG code runs without modification, and Go's powerful features are available in PRG syntax.

Harbour Compatible Syntax (98% parsing)

Full support for all Harbour/Clipper/xBase syntax:

FUNCTION, PROCEDURE, RETURN, LOCAL, STATIC, PRIVATE, PUBLIC
IF/ELSEIF/ELSE/ENDIF, DO CASE/CASE/OTHERWISE/ENDCASE
FOR/NEXT, FOR EACH/NEXT, DO WHILE/ENDDO
BEGIN SEQUENCE/RECOVER/END, SWITCH/CASE/ENDSWITCH
CLASS/DATA/METHOD/ACCESS/ASSIGN/ENDCLASS
USE, SELECT, SEEK, SKIP, GO, APPEND, REPLACE, DELETE, PACK
@ SAY/GET/READ, MENU TO, SET, INDEX ON

Five Go Extensions

1. IMPORT — Direct Go Package Access

IMPORT "strings"                    // Go standard library
IMPORT "database/sql"               // SQL database
IMPORT _ "modernc.org/sqlite"       // blank import (driver registration)
IMPORT myhttp "net/http"            // aliased import

After IMPORT, use directly from PRG:

IMPORT "strings"

PROCEDURE Main()
   LOCAL cResult
   cResult := strings.ToUpper("hello five")     // Direct Go function call
   ? strings.Contains(cResult, "FIVE")           // .T.
   ? strings.Split("a,b,c", ",")                 // {"a","b","c"}
   RETURN

No #pragma BEGINDUMP needed. IMPORT gives access to Go's entire ecosystem.

2. Multi-Return — Multiple Return Values

// Return multiple values from a function
FUNCTION GetUserInfo()
   RETURN "Charles", 30, "Seoul"

// Receive multiple values
cName, nAge, cCity := GetUserInfo()

// Discard unwanted values with blank identifier
_, nAge, _ := GetUserInfo()

Natural support for Go's (val, error) pattern:

IMPORT "database/sql"
db, err := sql.Open("sqlite", ":memory:")
IF err != NIL
   ? "Error:", err
ENDIF

3. DEFER — Automatic Cleanup

Executes when the function returns. Guaranteed even on errors.

PROCEDURE ProcessFile(cPath)
   LOCAL db
   db := sql.Open("sqlite", cPath)
   DEFER db:Close()                  // Auto-Close when function ends

   db:Exec("INSERT ...")             // Even if error occurs here
   db:Exec("UPDATE ...")             // db:Close() will always execute
   RETURN                            // ← DEFER executes here

More concise than Harbour's BEGIN SEQUENCE/RECOVER:

Before (Harbour):                    After (Five):
───────────────────────────────      ─────────────────────
BEGIN SEQUENCE                       db := SqlOpen(...)
   db := SqlOpen(...)                DEFER db:Close()
   db:Exec(...)                      db:Exec(...)
RECOVER                              RETURN
   db:Close()
END SEQUENCE
db:Close()

4. Slice — Sub-array / Sub-string

LOCAL aData := {"a", "b", "c", "d", "e"}

aSub := aData[2:4]          // {"b", "c", "d"}
aSub := aData[3:]           // {"c", "d", "e"}  (from 3 to end)
aSub := aData[:2]           // {"a", "b"}        (from start to 2)

Replaces verbose Harbour loops:

Before:                              After:
───────────────────────────────      ─────────────────────
LOCAL aSub := {}                     aSub := aData[3:7]
FOR i := 3 TO 7
   AAdd(aSub, aData[i])
NEXT

5. Parallel Assignment — Simultaneous Assign

// Swap values (no temp variable needed!)
a, b := b, a

// Simultaneous initialization
x, y, z := 1, 2, 3

6. Nil-Safe Operator — ?:

// Before: repeated NIL checks
IF oCustomer != NIL
   IF oCustomer:Address != NIL
      ? oCustomer:Address:City
   ENDIF
ENDIF

// Five: one line
? oCustomer?:Address?:City           // Returns NIL if any part is NIL

7. String Interpolation — f"..."

LOCAL cName := "Charles", nAge := 30

// Before
? "Name: " + cName + " Age: " + Str(nAge)

// Five
? f"Name: {cName}, Age: {nAge}"

// With format specifiers
? f"Price: {nPrice:.2f}, Count: {nCount:05d}"

8. CONST Block — Constants / Enums

CONST
   STATUS_ACTIVE  := 1
   STATUS_CLOSED  := 2
   STATUS_PENDING := 3
END CONST

9. SWITCH (Harbour compatible + extended)

// Standard Harbour syntax works as-is
SWITCH nStatus
CASE 1
   ? "Active"
CASE 2
   ? "Closed"
OTHERWISE
   ? "Unknown"
ENDSWITCH

Five Concurrency Syntax

10. Channel Operators — <-

ch := Channel()

ch <- "hello"                // Send to channel
msg := <- ch                 // Receive from channel

Harbour functions vs Five operators:

Harbour functions:                   Five operators:
───────────────────────────────      ─────────────────────
ChSend(ch, "hello")                  ch <- "hello"
msg := ChReceive(ch)                 msg := <- ch
ChSend(chOut, nResult)               chOut <- nResult

11. SPAWN / LAUNCH / GOROUTINE — Inline Goroutine

Three keywords, same behavior — choose your preference:

SPAWN     {|| DoHeavyWork() }
LAUNCH    {|| ProcessData() }
GOROUTINE {|| SendNotification() }

12. WATCH — Channel Multiplexing (Go select)

Monitor multiple channels simultaneously, process the first one ready:

WATCH
CASE msg := <- chMessages            // Message arrived
   ? "Message:", msg
CASE result := <- chResults          // Result arrived
   ? "Result:", result
CASE <- chTimeout                    // Timeout
   ? "Timeout!"
OTHERWISE                            // No channel ready
   ? "No channel ready"
END WATCH

Real-world pattern: Select fastest server response

SPAWN {|| DelayAndSend(0.1, chFast, "Fast Server") }
SPAWN {|| DelayAndSend(2.0, chSlow, "Slow Server") }
SPAWN {|| DelayAndSend(3.0, chTimeout, "TIMEOUT") }

WATCH
CASE cResult := <- chFast
   ? "Winner:", cResult              // ← Selected (fastest at 100ms)
CASE cResult := <- chSlow
   ? "Winner:", cResult
CASE <- chTimeout
   ? "Timeout!"
END WATCH

13. PARALLEL FOR — Parallel Loop

// Process 100K items across all CPU cores
PARALLEL FOR i := 1 TO 100000
   aResult[i] := ProcessItem(aData[i])
NEXT
// Automatically waits for all goroutines to complete

14. ASYNC / AWAIT — Asynchronous Execution

// Start heavy work in background
future := ASYNC HeavyQuery("SELECT * FROM big_table")

// Do other work (non-blocking)
? "Loading..."
PrepareUI()

// Wait for result
aRows := AWAIT future
? "Got", Len(aRows), "rows"

15. WITH TIMEOUT — Timeout Context

// Auto-cancel if not completed within 3 seconds
WITH TIMEOUT 3
   result := SlowNetworkCall()
END

IF result == NIL
   ? "Timeout!"
ENDIF

Direct Go Object Manipulation

pkg.Func() — Package Function Calls

IMPORT "strings"
IMPORT "math"
IMPORT "fmt"

? strings.ToUpper("hello")          // "HELLO"
? math.Sqrt(144)                     // 12
? fmt.Sprintf("%.2f", 3.14159)       // "3.14"

obj:Method() — Go Object Method Calls

IMPORT "database/sql"

db := sql.Open("sqlite", ":memory:")
db:Exec("CREATE TABLE test (id INTEGER)")
rows := db:Query("SELECT * FROM test")
DO WHILE rows:Next()
   ? rows:Column(1)
END
rows:Close()
db:Close()

Multiple Go Objects Simultaneously

dbSource := sql.Open("sqlite", "source.db")
dbTarget := sql.Open("sqlite", "target.db")

aRows := SqlScan(dbSource, "SELECT * FROM products")
FOR i := 1 TO Len(aRows)
   dbTarget:Exec("INSERT INTO inventory VALUES (...)")
NEXT

dbSource:Close()
dbTarget:Close()

Five vs Competitors

xBase Family Comparison

Feature Harbour xHarbour FiveWin Five
DBF/NTX/CDX Yes Yes Yes Yes
SQL Database No Limited ODBC All Go DBs
HTTP Server No No No net/http
WebSocket No No No Yes
Goroutine No No No Native
Channel <- No No No Yes
JSON Limited Limited Limited Go encoding/json
Cross-platform Partial Partial Windows Linux/Mac/Windows
Package ecosystem C libs C libs C libs All Go packages

Transpiler Comparison

Feature TypeScript→JS Kotlin→JVM Five (PRG→Go)
Type system Static→Dynamic Static→Static Dynamic→Static
Concurrency async/await coroutine goroutine+channel
External packages npm Maven Go modules
Build output JS code bytecode Native binary
Interop Direct JS Direct Java Direct Go (IMPORT)
Performance V8 runtime JVM runtime Native speed

What Makes Five Unique

  1. IMPORT gives access to all of Go — No #pragma BEGINDUMP needed
  2. Native binary output — Single executable, no JVM or V8 required
  3. goroutine + channel + WATCH — Full Go concurrency in PRG syntax
  4. 100% xBase compatible — Existing DBF/NTX/CDX code runs as-is
  5. FastPath optimization — Go function calls within 2x of native performance
  6. DEFER — Safe resource management, cleaner than BEGIN SEQUENCE
  7. Multi-Returna, b := Func(), natural Go (val, error) pattern
  8. f-string — String interpolation, f"Hello {name}"
  9. PARALLEL FOR — Automatic parallel processing of large datasets
  10. Nil-safe ?: — Safe chaining, no runtime errors from NIL

Performance

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 Call Type           Direct Go   Reflect    FastPath
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 strings.ToUpper        34ns      242ns       66ns
 strings.Contains        3ns      218ns       19ns
 math.Sqrt             0.1ns      173ns       16ns
 obj:Method()            —        412ns      235ns
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

 Throughput: 15M calls/sec (FastPath), 4.3M calls/sec (Method)
 Stress tested: 40K calls, 1MB strings, 10K arrays,
                20K concurrent goroutines, 5K random fuzz

Math: Harbour RTL + Go math Together

Five gives you two math systems in one file:

IMPORT "math"

PROCEDURE Main()
   LOCAL nVal

   // Harbour RTL — simple, no IMPORT needed
   ? Abs(-42.5)              // 42.5
   ? Sqrt(144)               // 12
   ? Round(3.14159, 2)       // 3.14
   ? Max(10, 20)             // 20

   // Go math — complete, 60+ functions
   ? math.Sin(math.Pi / 6)  // 0.5
   ? math.Pow(2, 10)         // 1024
   ? math.Hypot(3, 4)        // 5
   ? math.Log2(1024)          // 10

   // Combined — use both freely
   nVal := (1 / Sqrt(2 * math.Pi)) * Exp(-0.5 * math.Pow(0, 2))
   ? "Normal PDF at 0:", Round(nVal, 6)

   RETURN
Harbour RTL Go math
Functions 9 (Abs, Sqrt, Round, Int, Max, Min, Log, Exp, Mod) 60+
IMPORT needed No IMPORT "math"
Best for Business calculations Scientific/financial
Precision Standard IEEE 754
Trig/Hyperbolic No Sin, Cos, Tan, Sinh, Cosh, ...
Constants No Pi, E, Phi, Ln2, Sqrt2
Special values No NaN, Inf, MaxFloat64

Example Files

File Description
examples/go_native.prg Direct Go package usage with IMPORT only
examples/go_strings.prg Full strings package utilization
examples/go_typetest.prg 18 type conversion tests
examples/go_dual_db.prg Two SQLite databases simultaneously
examples/go_channel.prg Channel operators + WATCH + Pipeline
examples/go_httpserver.prg REST API server
examples/go_concurrent.prg Parallel data pipeline
examples/go_websocket.prg WebSocket chat server
examples/go_extensions.prg All 9 extension syntax demo
examples/go_math_compare.prg Harbour RTL vs Go math side-by-side
examples/godump_demo.prg HB_FUNC Go API