Harbour Complete Programming Book
Harbour Complete Programming Book
Guide
Table of Contents
4. Development Environment
3. Control Structures
1 / 70
Part III: Functions and Procedures
1. Defining Functions
4. Built-in Functions
4. SQL Integration
2. Text Processing
3. Network Programming
2. Multi-threading
2 / 70
3. Memory Management
4. Performance Optimization
What is Harbour?
Harbour is a free, open-source implementation of a cross-platform, multi-threading,
object-oriented, scriptable programming language. It maintains 100% compatibility
with CA-Clipper, making it an ideal modernization path for legacy xBase applications
while offering powerful new features for contemporary development.
Key Characteristics:
- Cross-platform: Runs on Windows, Linux, macOS, iOS, Android, BSD, Unix, and
more
- Object-oriented: Full OOP support with classes, inheritance, and polymorphism
- Multi-threading: Built-in support for concurrent programming
- Scriptable: Can be used for both compiled applications and scripts
- Compatible: 100% backward compatible with Clipper
- Extensible: Rich ecosystem of libraries and third-party integrations
3 / 70
History and Evolution
The journey of Harbour began in the golden age of database programming:
Development Advantages:
- Rapid application development
- Extensive built-in function library
- Powerful build system (hbmk2)
- Interactive development environment (hbrun)
- Strong community support
- Commercial-friendly licensing
Harbour Philosophy
Harbour embodies the philosophy of "write once, run everywhere" while
maintaining the simplicity and power that made xBase popular. Like a lighthouse
that provides both guidance and warning, Harbour offers:
4 / 70
• Safety: Strong error handling and debugging capabilities
Whether you're migrating from Clipper, exploring xBase for the first time, or seeking
to modernize existing applications, this book will serve as your trusted lighthouse,
guiding you safely through every aspect of Harbour development.
System Requirements
Minimum Requirements:
- Processor: 32-bit or 64-bit processor (x86, x86_64, ARM supported)
- Memory: 512 MB RAM (2 GB recommended)
- Storage: 50 MB for basic installation (500 MB for full development setup)
- Operating System: Any supported platform (see below)
C Compiler Requirements:
Harbour requires an ANSI C compiler for building:
5 / 70
- Windows: MinGW, MSVC, Clang, Borland C++, Intel C++, Watcom, Pelles C
- Linux: GCC, Clang
- macOS: Clang (via Xcode Command Line Tools)
- Unix/BSD: GCC, system-specific compilers
Supported Platforms
Harbour's cross-platform nature shines across an impressive array of systems:
Desktop Platforms:
- Windows (all versions from XP onwards)
- Linux (all major distributions)
- macOS (10.9+ and macOS 11+ for ARM)
- FreeBSD, NetBSD, OpenBSD
- Unix variants (Solaris, AIX, HP-UX)
Mobile Platforms:
- iOS (32-bit and 64-bit)
- Android (ARM, x86, x86_64)
Embedded/Specialized:
- DOS (DJGPP)
- OS/2
- QNX
- VxWorks
- Symbian
- BeOS/Haiku
Installation Methods
6 / 70
# Download from SourceForge
[Link]
Linux (Ubuntu/Debian):
# Install dependencies
sudo apt-get update
sudo apt-get install build-essential
macOS:
7 / 70
# Ensure you have required tools
make --version # GNU Make 3.81 or newer required
gcc --version # Or your preferred C compiler
git --version # For development builds
Build Configuration:
Compilation:
8 / 70
# Basic build (detects platform automatically)
make
# Platform-specific builds
make HB_PLATFORM=win HB_COMPILER=mingw # Windows with MinGW
make HB_PLATFORM=linux HB_COMPILER=gcc # Linux with GCC
make HB_PLATFORM=darwin HB_COMPILER=clang # macOS with Clang
# Debian/Ubuntu
sudo apt-get install harbour
# Red Hat/CentOS/Fedora
sudo yum install harbour
# or
sudo dnf install harbour
# Arch Linux
sudo pacman -S harbour
macOS Homebrew:
9 / 70
# Install Homebrew if not present
/bin/bash -c "$(curl -fsSL [Link]
Homebrew/install/HEAD/[Link])"
# Install Harbour
brew install harbour
Environment Configuration
Setting PATH Variables:
Windows:
Linux/macOS:
# Reload configuration
source ~/.bashrc
Environment Variables:
10 / 70
# Essential variables
export HB_ROOT=/path/to/harbour # Harbour installation
directory
export HB_PATH=%HB_ROOT%/bin # Harbour executables
export HB_LIB_INSTALL=%HB_ROOT%/lib # Library installation
path
export HB_INC_INSTALL=%HB_ROOT%/include # Header files path
# Development variables
export HB_BUILD_VERBOSE=yes # Verbose build output
export HB_BUILD_JOBS=4 # Parallel compilation
jobs
export HB_CCACHE=yes # Use ccache if available
11 / 70
# Check Harbour compiler
harbour --version
# Test compilation
echo 'PROCEDURE Main()' > [Link]
echo ' ? "Hello, Harbour!"' >> [Link]
echo 'RETURN' >> [Link]
Expected Output:
12 / 70
// .vscode/[Link]
{
"[Link]": {
"*.prg": "harbour",
"*.ch": "harbour"
},
"[Link]": "/usr/local/harbour/bin/harbour",
"[Link]": "/usr/local/harbour/bin/hbmk2"
}
Sublime Text:
# Missing dependencies
sudo apt-get install build-essential # Linux
xcode-select --install # macOS
Path Issues:
13 / 70
# Verify Harbour is in PATH
which harbour
which hbmk2
# Check permissions
ls -la /usr/local/harbour/bin/
chmod +x /usr/local/harbour/bin/*
Library Linking:
# Missing libraries
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/harbour/lib
14 / 70
// [Link] - Your first Harbour program
PROCEDURE Main()
? "Hello, World!"
? "Welcome to Harbour Programming!"
RETURN
Expected Output:
Hello, World!
Welcome to Harbour Programming!
1. Procedure Declaration:
PROCEDURE Main()
• Main() is the entry point—Harbour automatically calls this when the program
starts
15 / 70
2. Output Statements:
? "Hello, World!"
3. Return Statement:
RETURN
16 / 70
// enhanced_hello.prg
PROCEDURE Main()
// Variable declarations
LOCAL cName := "Harbour Developer"
LOCAL dToday := Date()
LOCAL nYear := Year(dToday)
LOCAL lIsModern := (nYear >= 2020)
// Conditional output
IF lIsModern
? "You're programming in the modern era!"
ELSE
? "Classic programming never goes out of style!"
ENDIF
?
? "Happy programming!"
RETURN
1. Variable Declaration:
17 / 70
LOCAL cName := "Harbour Developer" // String variable
LOCAL dToday := Date() // Date variable
LOCAL nYear := Year(dToday) // Numeric variable
LOCAL lIsModern := (nYear >= 2020) // Logical variable
2. Hungarian Notation:
Harbour commonly uses Hungarian notation for variable names:
- c prefix for Character (string) variables
- n prefix for Numeric variables
- d prefix for Date variables
- l prefix for Logical (boolean) variables
- a prefix for Array variables
- o prefix for Object variables
3. String Operations:
4. Function Calls:
5. Conditional Logic:
IF lIsModern
// Code for modern era
ELSE
// Code for classic era
ENDIF
18 / 70
Interactive Programs
Let's create a program that interacts with the user:
19 / 70
// interactive_hello.prg
PROCEDURE Main()
LOCAL cName, cAge, nAge, cResponse
DO CASE
CASE nAge < 18
? "You're quite young to be learning programming!"
CASE nAge >= 18 .AND. nAge < 65
? "Perfect age for mastering Harbour!"
OTHERWISE
? "Wisdom and experience are great programming assets!"
ENDCASE
20 / 70
// Calculate birth year
? "You were born around:", Str(Year(Date()) - nAge)
?
?? "Press any key to continue..."
Inkey(0)
RETURN
New Concepts:
1. Screen Control:
2. Input Handling:
3. String Functions:
4. Multi-way Branching:
21 / 70
DO CASE
CASE condition1
// Code
CASE condition2
// Code
OTHERWISE
// Default code
ENDCASE
5. User Interaction:
22 / 70
// array_demo.prg
PROCEDURE Main()
LOCAL aColors := {"Red", "Green", "Blue", "Yellow", "Purple"}
LOCAL aNumbers := {10, 20, 30, 40, 50}
LOCAL aMixed := {"John", 25, Date(), .T., {1, 2, 3}}
LOCAL i
? "Array Demonstration"
? "=================="
?
?
? "Numbers array (using FOR EACH):"
FOR EACH item IN aNumbers
? " Item " + Str(HB_EnumIndex()) + ": " + Str(item)
NEXT
?
? "Mixed array information:"
? " Array length:", Len(aMixed)
? " First item (string):", aMixed[1]
? " Second item (number):", aMixed[2]
? " Third item (date):", aMixed[3]
? " Fourth item (logical):", aMixed[4]
? " Fifth item (array):", aMixed[5][1], aMixed[5][2], aMixed[5]
[3]
RETURN
23 / 70
Array Concepts:
1. Array Declaration:
2. Array Access:
3. Array Iteration:
24 / 70
// error_demo.prg
PROCEDURE Main()
LOCAL nResult, nDivisor := 0
? "Error caught!"
? "Error description:", oError:Description
? "Error operation:", oError:Operation
? "Continuing program execution..."
END SEQUENCE
?
? "Program completed successfully!"
RETURN
25 / 70
// Always include meaningful comments
// Use consistent indentation (3-4 spaces recommended)
// Group related functionality together
2. Variable Naming:
3. Error Prevention:
// Validate inputs
IF Empty(cName)
cName := "Anonymous"
ENDIF
4. Documentation:
26 / 70
/*
* Function: CalculateTotal
* Purpose: Calculate total with tax
* Parameters: nAmount - base amount
* nTaxRate - tax rate (decimal)
* Returns: Total amount including tax
*/
FUNCTION CalculateTotal(nAmount, nTaxRate)
RETURN nAmount * (1 + nTaxRate)
Variables:
Control Structures:
27 / 70
IF condition ... ENDIF // Conditional
FOR counter := start TO end ... NEXT // Counting loop
WHILE condition ... ENDDO // Conditional loop
FOR EACH item IN array ... NEXT // Iteration loop
DO CASE ... CASE ... OTHERWISE ... ENDCASE // Multi-way branch
Congratulations! You've taken your first steps into Harbour programming. Like a
ship safely guided to harbor by a lighthouse, you now have the fundamental
navigation tools to explore the deeper waters of this powerful language.
Core Tools:
- harbour: The compiler that translates Harbour source to C code
- hbmk2: The build tool and project manager
- hbrun: The script runner and interactive shell
- hbformat: Code formatter for consistent styling
- hbtest: Testing framework for quality assurance
Basic Usage:
28 / 70
# Compile single file
hbmk2 [Link]
29 / 70
# Create [Link]
-o=myapplication
-w3
-es2
# Source files
[Link]
[Link]
[Link]
# Libraries
-luser32
-lgdi32
# Include paths
-I../common/include
# Library paths
-L../common/lib
# Preprocessor defines
-DRELEASE_BUILD
-DHB_THREAD_SUPPORT
30 / 70
# Development builds
hbmk2 [Link] -debug -trace
# Production builds
hbmk2 [Link] -optim -strip
# Cross-platform builds
hbmk2 [Link] -platform=linux
hbmk2 [Link] -platform=win -compiler=mingw
Script Execution:
# Interactive shell
hbrun
# One-liner execution
hbrun -e "? 'Hello from command line'"
31 / 70
// In hbrun interactive mode
hb> ? "Hello, Interactive Harbour!"
Hello, Interactive Harbour!
32 / 70
MyProject/
├── src/
│ ├── [Link]
│ ├── models/
│ │ ├── [Link]
│ │ └── [Link]
│ ├── views/
│ │ ├── [Link]
│ │ └── [Link]
│ └── utils/
│ ├── [Link]
│ └── [Link]
├── include/
│ ├── [Link]
│ └── [Link]
├── tests/
│ ├── test_models.prg
│ └── test_utils.prg
├── docs/
│ └── [Link]
├── build/
└── [Link]
Modular Programming:
33 / 70
// In include/[Link]
#define APP_NAME "My Application"
#define APP_VERSION "1.0.0"
#define APP_COPYRIGHT "Copyright (c) 2024"
// Function prototypes
ANNOUNCE GetCustomerName
ANNOUNCE CalculateTotal
ANNOUNCE ValidateEmail
34 / 70
// In src/models/[Link]
#include "[Link]"
oCustomer:Name := cName
oCustomer:Email := cEmail
oCustomer:Phone := cPhone
IF ValidateCustomer(oCustomer)
RETURN oCustomer
ENDIF
RETURN NIL
FUNCTION ValidateCustomer(oCustomer)
RETURN !Empty(oCustomer:Name) .AND. ;
ValidateEmail(oCustomer:Email)
.vscode/[Link]:
35 / 70
{
"[Link]": {
"*.prg": "harbour",
"*.ch": "harbour-header"
},
"[Link]": 3,
"[Link]": true,
"[Link]": [80, 120],
"[Link]": "utf8",
"[Link]": "\n"
}
.vscode/[Link]:
36 / 70
{
"version": "2.0.0",
"tasks": [
{
"label": "Build Harbour Project",
"type": "shell",
"command": "hbmk2",
"args": ["${workspaceFolder}/[Link]"],
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"echo": true,
"reveal": "always",
"focus": false,
"panel": "shared"
},
"problemMatcher": []
},
{
"label": "Run Harbour Script",
"type": "shell",
"command": "hbrun",
"args": ["${file}"],
"group": "test"
}
]
}
[Link]-syntax:
37 / 70
name: Harbour
file_extensions: [prg, ch]
scope: [Link]
contexts:
main:
- match: '(?i)\b(function|procedure|class|method)\b'
scope: [Link]
- match: '(?i)\b(local|static|private|public)\b'
scope: [Link]
- match: '(?i)\b(if|else|endif|while|enddo|for|next|do case|
endcase)\b'
scope: [Link]
- match: '"[^"]*"'
scope: [Link]
- match: "//.*$"
scope: [Link]
- match: '/\*.*?\*/'
scope: [Link]
Debugging Techniques
Built-in Debugging:
38 / 70
// Debug output
? "Debug: Variable value =", nValue
?? " at line", ProcLine()
// Conditional debugging
#ifdef DEBUG
? "Debug mode: Processing record", nRecNo
#endif
Advanced Debugging:
39 / 70
// Error context information
FUNCTION MyFunction()
LOCAL nResult
LOCAL i
FOR i := 1 TO 10
IF !Empty(ProcName(i))
? " ", i, ProcName(i), ProcLine(i)
ENDIF
NEXT
BREAK oError
END SEQUENCE
RETURN nResult
Debugging Macros:
40 / 70
// In include/[Link]
#ifdef DEBUG
#define DBG(x) (? "DBG:", x)
#define TRACE(x) (? "TRACE: " + ProcName() + "(" +
Str(ProcLine()) + "): ", x)
#else
#define DBG(x)
#define TRACE(x)
#endif
// Usage in code
#include "[Link]"
FUNCTION ProcessData(aData)
TRACE("Starting with " + Str(Len(aData)) + " records")
LOCAL nCount := 0
FOR EACH item IN aData
DBG("Processing item: " + item)
nCount++
NEXT
Performance Profiling
Simple Timing:
41 / 70
FUNCTION ProfileFunction()
LOCAL nStart := Seconds()
RETURN nElapsed
Detailed Profiling:
42 / 70
STATIC s_aProfileData := {}
FUNCTION StartProfile(cFunction)
LOCAL nPos := AScan(s_aProfileData, {|a| a[1] == cFunction})
IF nPos == 0
AAdd(s_aProfileData, {cFunction, 0, 0, Seconds()})
nPos := Len(s_aProfileData)
ELSE
s_aProfileData[nPos][4] := Seconds()
ENDIF
RETURN nPos
FUNCTION EndProfile(nHandle)
LOCAL nElapsed := Seconds() - s_aProfileData[nHandle][4]
RETURN nElapsed
FUNCTION ShowProfile()
? "Function Profiling Results:"
? "=========================="
? "Function", Space(20), "Calls", "Total Time", "Avg Time"
RETURN NIL
43 / 70
Version Control Integration
Git Configuration for Harbour:
.gitignore:
44 / 70
# Compiled binaries
*.exe
*.dll
*.so
*.dylib
# Object files
*.o
*.obj
*.c
*.cpp
# Build directories
build/
dist/
release/
debug/
# Harbour specific
*.hrb
*.hbl
*.hbx
# Editor files
*.bak
*.swp
*~
.vscode/
*.sublime-workspace
# OS specific
.DS_Store
[Link]
45 / 70
Git Hooks:
#!/bin/sh
# .git/hooks/pre-commit
# Format code before commit
46 / 70
// In tests/test_runner.prg
#include "[Link]"
PROCEDURE Main()
LOCAL oTest := HBTest():New("My Application Tests")
// Display results
oTest:Report()
RETURN
FUNCTION TestStringUtils()
LOCAL oSuite := HBTestSuite():New()
RETURN oSuite
Continuous Integration
GitHub Actions Workflow (.github/workflows/[Link]):
47 / 70
name: Harbour CI
jobs:
build:
runs-on: ${{ [Link] }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macOS-latest]
steps:
- uses: actions/checkout@v2
48 / 70
Chapter 5: Data Types and Variables
Understanding data types in Harbour is like understanding the different types of
signals a lighthouse can emit—each serves a specific purpose and conveys particular
information. Harbour's rich type system provides the foundation for building robust
applications while maintaining the simplicity that makes the language accessible.
Scalar Types:
- NIL: Represents absence of value
- Logical: Boolean values (.T. or .F.)
- Numeric: Integer and floating-point numbers
- Date: Date values with special handling
- String: Character sequences
- Pointer: References to functions or memory
Complex Types:
- Array: Ordered collections of any data type
- Object: Class instances with properties and methods
- CodeBlock: Executable code snippets
- Hash: Key-value pair collections
49 / 70
PROCEDURE Main()
LOCAL xValue := NIL
LOCAL cName, nAge, dBirth // Uninitialized variables are NIL
RETURN
NIL Characteristics:
- Default value for uninitialized variables
- Evaluates to .F. in logical contexts
- Returns 0 when used in numeric contexts
- Returns empty string when used in string contexts
50 / 70
PROCEDURE Main()
LOCAL lActive := .T. // True
LOCAL lVisible := .F. // False
LOCAL lResult
// Logical operations
lResult := lActive .AND. lVisible // .F.
? "AND result:", lResult
// Logical expressions
LOCAL nAge := 25
LOCAL lCanVote := (nAge >= 18)
? "Can vote:", lCanVote // .T.
// Converting to logical
? "Logical of 1:", (1 == .T.) // .T.
? "Logical of 0:", (0 == .F.) // .T.
? "Logical of 'Y':", ('Y' $ 'YyTt') // .T.
RETURN
Logical Constants:
- .T. , .TRUE. , .Y. - True values
- .F. , .FALSE. , .N. - False values
51 / 70
Numeric Data Type
Harbour handles both integer and floating-point numbers seamlessly:
52 / 70
PROCEDURE Main()
// Integer numbers
LOCAL nCount := 42
LOCAL nNegative := -17
LOCAL nHex := 0xFF // Hexadecimal (255)
LOCAL nOctal := 0o777 // Octal (511)
// Floating-point numbers
LOCAL nPi := 3.14159
LOCAL nScientific := 1.23e-4
LOCAL nPercent := 15.75
? "Integer:", nCount
? "Hexadecimal:", nHex
? "Float:", nPi
? "Scientific:", nScientific
// Numeric operations
LOCAL nResult
nResult := nCount + 10 // Addition
? "Addition:", nResult
// Numeric functions
53 / 70
? "Absolute:", Abs(-42) // 42
? "Round:", Round(3.14159, 2) // 3.14
? "Int:", Int(3.14159) // 3
? "Max:", Max(10, 20, 15) // 20
? "Min:", Min(10, 20, 15) // 10
RETURN
Numeric Precision:
- Integers: Platform-dependent (typically 32 or 64-bit)
- Floating-point: IEEE 754 double precision
- Decimal precision: Configurable (default 16 digits)
54 / 70
PROCEDURE Main()
// String declaration methods
LOCAL cName := "John Doe" // Double quotes
LOCAL cAddress := 'Main Street' // Single quotes
LOCAL cLong := [Long text string] // Square brackets
LOCAL cEmpty := "" // Empty string
? "Name:", cName
? "Length:", Len(cName) // 8
// String concatenation
LOCAL cFull := cName + " lives on " + cAddress
? "Full:", cFull
// String functions
? "Upper:", Upper(cName) // JOHN DOE
? "Lower:", Lower(cName) // john doe
? "Proper:", Proper(cName) // John Doe
// String searching
? "Position of 'John':", At("John", cName) // 1
? "Contains 'Doe':", "Doe" $ cName // .T.
// String extraction
? "Left 4:", Left(cName, 4) // John
? "Right 3:", Right(cName, 3) // Doe
? "Substring:", SubStr(cName, 6, 3) // Doe
// String modification
LOCAL cPadded := PadL(cName, 15, "*")
? "Left padded:", cPadded // *******John Doe
55 / 70
? "Trimmed:", AllTrim(" " + cName + " ") // John Doe
// String replacement
? "Replaced:", StrTran(cName, "Doe", "Smith") // John Smith
RETURN
String Features:
- Dynamic length (limited by available memory)
- ASCII and UTF-8 encoding support
- Null-terminated internally (C compatibility)
- 1-based indexing for substring operations
56 / 70
PROCEDURE Main()
// Date creation
LOCAL dToday := Date() // Current date
LOCAL dBirth := CToD("12/25/1990") // String to date
LOCAL dLiteral := 0d19901225 // Date literal (YYYYMMDD)
LOCAL dEmpty := CToD("") // Empty date
? "Today:", dToday
? "Birth:", dBirth
? "Literal:", dLiteral
? "Empty:", dEmpty
// Date functions
? "Day:", Day(dBirth) // 25
? "Month:", Month(dBirth) // 12
? "Year:", Year(dBirth) // 1990
? "Day of week:", DoW(dBirth) // 1-7 (Sunday=1)
? "Day name:", CDoW(dBirth) // Day name
? "Month name:", CMonth(dBirth) // Month name
// Date arithmetic
LOCAL dFuture := dToday + 30 // Add 30 days
LOCAL nDays := dToday - dBirth // Days between dates
// Date formatting
? "Default format:", DToC(dBirth) // MM/DD/YY or DD/MM/YY
? "SQL format:", DToS(dBirth) // YYYYMMDD
? "Transform:", Transform(dBirth, "@D") // Formatted display
// Date validation
? "Valid date:", !Empty(dBirth) // .T.
? "Empty date:", Empty(dEmpty) // .T.
57 / 70
RETURN
Date System:
- Internal storage: Julian day numbers
- Range: From year 0001 to year 9999
- Leap year handling: Automatic
- Date format: Controlled by SET DATE and SET CENTURY
58 / 70
PROCEDURE Main()
// Array creation
LOCAL aNumbers := {1, 2, 3, 4, 5} // Literal
LOCAL aNames := {"John", "Mary", "Bob"} // String array
LOCAL aMixed := {1, "Two", .T., Date()} // Mixed types
LOCAL aEmpty := {} // Empty array
LOCAL aDynamic := Array(10) // Array with 10 NIL
elements
? "Numbers:", Len(aNumbers) // 5
? "First number:", aNumbers[1] // 1
? "Last number:", aNumbers[Len(aNumbers)] // 5
// Array modification
aNumbers[1] := 100 // Change element
AAdd(aNumbers, 6) // Add element
ADel(aNumbers, 2) // Delete element
(sets to NIL)
ASize(aNumbers, 4) // Resize array
// Multidimensional arrays
LOCAL aMatrix := {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
? "Matrix element [2,3]:", aMatrix[2][3] // 6
// Array functions
LOCAL aSource := {10, 20, 30}
LOCAL aDest := {}
59 / 70
LOCAL nPos := AScan(aNames, "Mary") // Find element
? "Mary position:", nPos // 2
// Array iteration
? "Array contents:"
FOR EACH item IN aNames
? " Item " + Str(HB_EnumIndex()) + ":", item
NEXT
RETURN
Array Characteristics:
- 1-based indexing
- Dynamic sizing
- Heterogeneous (can mix data types)
- Pass by reference
- Unlimited nesting depth
60 / 70
PROCEDURE Main()
// Hash creation
LOCAL hPerson := {"name" => "John", "age" => 30, "active"
=> .T.}
LOCAL hEmpty := {=>} // Empty hash
LOCAL hTyped := hb_Hash() // Using function
// Hash modification
hPerson["email"] := "john@[Link]" // Add key
hPerson["age"] := 31 // Modify value
? "Email:", hPerson["email"]
? "New age:", hPerson["age"]
// Hash functions
? "Hash size:", Len(hPerson) // 4
? "Has name key:", "name" $ hPerson // .T.
// Hash iteration
? "Hash contents:"
FOR EACH key IN aKeys
? " " + key + ":", hPerson[key]
NEXT
RETURN
61 / 70
CodeBlock Data Type
CodeBlocks are executable code snippets that can be stored and executed:
PROCEDURE Main()
// Simple codeblocks
LOCAL bGreeting := {|| "Hello, World!"}
LOCAL bAdd := {|x, y| x + y}
LOCAL bCheck := {|n| n > 0}
// Conditional codeblock
LOCAL bCondition := {|x| x % 2 == 0} // Even numbers
LOCAL nPos := AScan(aNumbers, bCondition)
? "First even position:", nPos // 1 (value 2)
// Complex codeblock
LOCAL bFormatter := {|name, age| ;
"Name: " + name + ", Age: " + Str(age)}
RETURN
62 / 70
Variable Scoping
Harbour provides four levels of variable scope:
63 / 70
// Global variables (visible everywhere)
PUBLIC g_cAppName := "My Application"
PUBLIC g_nVersion := 1.0
PROCEDURE Main()
// Local variables (function/procedure scope)
LOCAL cUser := "Administrator"
LOCAL nCount := 0
TestFunction()
RETURN
FUNCTION TestFunction()
// Static variables (persistent between calls)
STATIC nCallCount := 0
nCallCount++
64 / 70
RETURN nCallCount
Scope Rules:
- LOCAL: Visible only within current function/procedure
- STATIC: Persistent between function calls, visible within function
- PRIVATE: Dynamic scope, visible to called functions
- PUBLIC: Global scope, visible everywhere
65 / 70
// Character (string) variables
LOCAL cName := "John"
LOCAL cFileName := "[Link]"
// Numeric variables
LOCAL nCount := 10
LOCAL nAmount := 1500.50
// Date variables
LOCAL dToday := Date()
LOCAL dBirth := CToD("01/01/1990")
// Logical variables
LOCAL lActive := .T.
LOCAL lFound := .F.
// Array variables
LOCAL aItems := {}
LOCAL aCustomers := {}
// Object variables
LOCAL oCustomer := Customer():New()
LOCAL oWindow := Window():New()
// Hash variables
LOCAL hConfig := {=>}
LOCAL hLookup := {=>}
// Codeblock variables
LOCAL bFilter := {|x| x > 0}
LOCAL bSort := {|a, b| a < b}
// Pointer variables
LOCAL pFunction := @MyFunction()
66 / 70
// Mixed/unknown type
LOCAL xValue := NIL
LOCAL xResult
PROCEDURE Main()
LOCAL xValue := "123"
// Type checking
? "Type:", ValType(xValue) // C (Character)
? "Is string:", ValType(xValue) == "C" // .T.
? "Is numeric:", ValType(xValue) == "N" // .F.
// Type conversion
LOCAL nNumber := Val(xValue) // String to number
? "Converted number:", nNumber // 123
RETURN
67 / 70
Understanding Harbour's data types is fundamental to effective programming. Like
understanding the different types of signals from a lighthouse, mastering these data
types will help you communicate clearly and effectively in your code, building
applications that are both robust and maintainable.
[The book continues with the remaining 25 chapters covering all aspects of Harbour
programming...]
Quick Reference
68 / 70
Essential Functions
// Type checking
ValType(value) // Returns type letter
Empty(value) // Checks for empty/NIL
Len(value) // Length of strings/arrays/hashes
// String functions
Upper(string) // Convert to uppercase
Lower(string) // Convert to lowercase
AllTrim(string) // Remove leading/trailing spaces
SubStr(string, start, length) // Extract substring
At(search, string) // Find position of substring
// Array functions
AAdd(array, item) // Add element
ADel(array, position) // Delete element
ASize(array, newsize) // Resize array
AScan(array, value) // Find element
// Date functions
Date() // Current date
Year(date) // Extract year
Month(date) // Extract month
Day(date) // Extract day
// Conversion functions
Val(string) // String to number
Str(number) // Number to string
CToD(string) // String to date
DToC(date) // Date to string
This comprehensive foundation in Harbour's data types and variables provides the
essential knowledge needed to build robust applications. In the next chapter, we'll
69 / 70
explore operators and expressions that work with these data types to create
powerful programming logic.
70 / 70