Harbour Basics
Data Types and Structures
Harbour has a flexible set of data types and structures. Variables are dynamic, with their type determined at runtime.
- nil: Represents a variable with no value.
- string: A string of characters.
- numeric: For both integer and floating-point numbers.
- date: Stores a calendar date.
- datetime: Stores both a date and a time.
- logical: A boolean value that is either
.t.(true) or.f.(false). - array: A dynamic, multi-dimensional collection of elements of any type.
- codeblock: A self-contained block of code stored in a variable for later execution.
- object: An instance of a class.
- hash: A data structure that stores key-value pairs, allowing for quick lookups (associative array).
- pointer: A variable that holds the memory address of another variable or object.
Variable Scopes
Harbour uses different keywords to define the scope, or visibility, of a variable.
- local: The most common scope. A
localvariable is only visible within the function or method where it is declared. - private: A variable visible within the current function and any other functions it calls.
- public: A variable that is globally visible throughout the entire program. Use this sparingly to avoid naming conflicts.
- static: A special type of variable that retains its value between function calls. A
staticvariable is declared within a function but its value persists, unlike alocalvariable which is re-initialized on each call.
Variable type declaration
Harbour allows to declare the type of variables but it is only a source code decoration and it's ignored by the compiler. The list of supported types is: anytype, array, codeblock, class, date, datetime, hash, logical, numeric, object, pointer, symbol.
- local var1 as string, var2 as numeric or local var1 as string := "foo", var2 as numeric := 16.
Class, Function, and Hash Examples
Harbour supports object-oriented programming (OOP) for defining classes, which act as blueprints for objects.
#include "dothrb.ch"
function main()
local oMyCar := new Car("Ford", "Fiesta", 1993)
outstd(oMyCar:getDetails())
return nil
// Class specification
class Car
var make
var model
var year
method init constructor
method getDetails
end class
// Class implementation
method init( cMake, cModel, nYear ) class Car
::make := cMake
::model := cModel
::year := nYear
return Self
method getDetails() class Car
return "Make: " + ::make + ", Model: " + ::model + ", Year: " + hb_ntos(::year)
In this example, the Car class has var (instance variables) and methods (functions) that operate on that data. The init() method is a constructor, and getDetails() is a regular method.
Harbour also uses functions, which are independent blocks of code that can be called and reused.
#include "dothrb.ch"
function main()
outstd(sumNumbers(5, 3))
return nil
function sumNumbers( nNum1, nNum2 )
local nResult := nNum1 + nNum2
return nResult
The function keyword defines a function named sumNumbers that accepts two arguments. The local keyword declares a variable that is only accessible within the function. The return statement sends a value back to the caller.
Here is an example of a hash (or associative array) in Harbour.
#include "dothrb.ch"
function main()
local oPerson := { "name" => "John Doe", "age" => 30, "city" => "New York" }
outstd(oPerson["name"], hb_eol()) // Output: John Doe
outstd(oPerson["age"], hb_eol()) // Output: 30
return nil
In this example, the curly braces {} and the => operator are used to define a hash with key-value pairs. Values are accessed by their corresponding keys inside square brackets [].
Statements
Harbour uses various statements to control program flow:
- assignment: The
:=operator assigns a value to a variable. - conditional statements:
if...elseif...else...end ifanddo case...case...otherwise...end caseexecute code blocks based on conditions. Theswitch...case...otherwise...end switchstructure is also available as a modern alternative for multi-choice scenarios. - loops:
for...next,for each...next,do while...end do, andwhile...end whileare used for repetitive tasks. Thewhileloop is an alternative todo while, providing a simple loop with a single condition at the start. - error handling: The
begin sequence...break...end sequenceconstruct provides a structured way to handle errors. - function calls: A function is executed by its name followed by its arguments in parentheses.
Dynamic Capabilities
Harbour's dynamic capabilities are a key part of its power and flexibility.
- Macro Operator (
&): This is a powerful feature that allows for runtime code compilation. The compiler at runtime evaluates the expression following the ampersand&, compiles it, and executes the resulting code. This means you can create dynamic expressions on the fly based on user input or other program variables. - Regex Support: Harbour includes support for regular expressions (regex) through its built-in functions. Regular expressions are a powerful tool for pattern matching and manipulation of strings.
Operators and Precedence
Harbour includes a comprehensive set of operators for performing various operations. The precedence of these operators determines the order in which they are evaluated in an expression. A higher precedence means the operator is evaluated first.
Logical Operators
- .and.: Logical AND.
- .or.: Logical OR.
- !: Logical NOT.
Comparison Operators
==(exact equality),<(less than),>(greater than),<=(less than or equal to),>=(greater than or equal to),<>or!=(not equal to).
Arithmetic Operators
+(addition),-(subtraction),*(multiplication),/(division),^or**(exponentiation).
Bitwise Operators
These operators work directly on the individual bits of numeric values.
!~: Bitwise NOT.&~: Bitwise AND.|~: Bitwise OR.^~: Bitwise XOR.<<: Left Shift.>>: Right Shift.
Operator Precedence (Highest to Lowest)
- Prefix Operators: Unary
+,-,!,++,--, etc. - Exponentiation:
^and**. - Multiplication and Division:
*,/. - Addition and Subtraction:
+,-. - Comparison:
==,<>,!=,>,<,>=,<=. - Logical NOT:
.not.. - Logical AND:
.and.. - Logical OR:
.or.. - Assignment:
:=.
Parentheses () can always be used to override the default precedence and force a specific order of evaluation.
Preprocessor
The Harbour preprocessor processes source code before compilation, simplifying it and enabling conditional logic.
#define: Defines a macro or symbolic constant.#include: Inserts the content of another source file.#if,#ifdef,#ifndef: Directives for conditional compilation, allowing for different code to be compiled for various platforms or features.#xcommand,#xtranslate: Powerful directives for creating custom syntax.