Harbour as every xBase language is case insensitive and can optionally accept keywords written just by their first four characters.
Built-in data types Harbour has six scalar types:
Nil,
String,
Date,
Logical,
Numeric,
Pointer, and four complex types:
Array,
Object,
CodeBlock, and
Hash. A scalar holds a single value, such as a string, numeric, or reference to any other type. Arrays are ordered lists of scalars or complex types, indexed by number, starting at 1. Hashes, or
associative arrays, are unordered collections of any type values indexed by their associated key, which may be of any scalar or complex type. Literal (static) representation of scalar types: • Nil: • String: • Date: • Logical: • Numeric: Complex Types may also be represent as literal values: • Array: { "String", 1, { "Nested Array" }, .T., FunctionCall(), @FunctionPointer() } •
CodeBlock: { |Arg1, ArgN| Arg1 := ArgN + OuterVar + FunctionCall() } • Hash: { "Name" => "John", 1 => "Numeric key", "Name2" => { "Nested" => "Hash" } } Hashes may use
any type including other Hashes as the
Key for any element. Hashes and Arrays may contain
any type as the
Value of any member, including nesting arrays, and Hashes. Codeblocks may have references to Variables of the Procedure/Function>method in which it was defined. Such Codeblocks may be returned as a value, or by means of an argument passed , in such case the Codeblock will "outlive" the routine in which it was defined, and any variables it references, will be a variable. Detached variables will maintain their value for as long as a Codeblock referencing them still exists. Such values will be shared with any other Codeblock which may have access to those same variables. If the Codeblock did not outlive its containing routine, and will be evaluated within the lifetime of the routine in which it is defined, changes to its
Detached Variables(s) by means of its evaluation, will be reflected back at its parent routine. Codeblocks can be evaluated any number of times, by means of the Eval(
BlockExp ) function.
Variables All types can be assigned to named variables. Named variable identifiers are 1 to 63 ASCII characters long, start with [A-Z|_] and further consist of the characters [A-Z|0–9|_] up to a maximum of 63 characters. Named variables are not case sensitive.
Variables have one of the following scopes: • : Visible only within the routine which declared it. Value is lost upon exit of the routine. • : Visible only within the routine which declared it. Value is preserved for subsequent invocations of the routine. If a STATIC variable is declared before any Procedure/Function/Method is defined, it has a MODULE scope, and is visible within any routine defined within that same source file, it will maintain its life for the duration of the application lifetime. • : Visible within the routine which declared it, and all routines by that routine. • : Visible by routines in the same application. and are resolved at compile time, and thus are much faster than and variables which are dynamic entities accessed by means of a runtime
Symbol table. For this same reason, and variables are exposed to the Macro compiler, and any macro code which attempts to reference them will generate a runtime error. Due to the dynamic nature of and variables, they can be created and destroyed at runtime and can be accessed and modified by means of runtime macros or by Codeblocks created on the fly.
Control structures The basic control structures include all of the standard
dBase, and
Clipper control structures as well as additional ones inspired by the
C or
Java programming languages:
Loops [DO] WHILE
ConditionExp ... [LOOP] [EXIT] END[DO] FOR
Var :=
InitExp TO
EndExp [STEP
StepExp]
... [LOOP] [EXIT] NEXT FOR EACH
Var IN
CollectionExp ... [
Var:__enumIndex()] [LOOP] [EXIT] NEXT • The
... is a sequence of one or more Harbour statements, and square brackets [] denote optional syntax. • The
Var:__enumIndex() may be optionally used to retrieve the current iteration index (1 based). • The
LOOP statement restarts the current iteration of the enclosing loop structure, and if the enclosing loop is a
FOR or
FOR EACH loop, it increases the iterator, moving to the next iteration of the loop. • The
EXIT statement immediately terminates execution of the enclosing loop structure. • The
NEXT statement closes the control structure and moves to the next iteration of loop structure. In the
FOR statement, the
assignment expression is evaluated prior to the first loop iteration. The
TO expression is evaluated and compared against the value of the control variable, prior to each iteration, and the loop is terminated if it evaluates to a numeric value greater than the numeric value of the control variable. The optional
STEP expression is evaluated after each iteration, prior to deciding whether to perform the next iteration. In
FOR EACH, the
Var variable will have the value (scalar, or complex) of the respective element in the collection value. The collection expression may be an Array (of any type or combinations of types), a Hash Table, or an Object type.
IF statements IF
CondExp ... [ELSEIF]
CondExp ... [ELSE]
... END[IF]
... represents 0 or more
statement(s). The condition expression(s) has to evaluate to a
LOGICAL value.
SWITCH statements Harbour supports a SWITCH construct inspired by the C implementation of switch(). SWITCH
SwitchExp CASE
LiteralExp ... [EXIT] [CASE
LiteralExp]
... [EXIT] [OTHERWISE]
... END[SWITCH] • The
LiteralExp must be a compiled time resolvable numeric expression, and may involve operators, as long as such operators involve compile time static value. • The
EXIT optional statement is the equivalent of the C statement
break, and if present, execution of the SWITCH structure will end when the EXIT statement is reached, otherwise it will continue with the first statement below the next CASE statement (fall through).
BEGIN SEQUENCE statements ... [BREAK] [Break( [
Exp] )]
Var]
... or: The structure allows for a well behaved abortion of any sequence, even when crossing nested procedures/functions. This means that a called procedure/function, may issue a statement, or a Break() expression, to force unfolding of any nested procedure/functions, all the way back to the first outer structure, either after its respective statement, or a clause if present. The Break statement may optionally pass any type of expression, which may be accepted by the statement to allow further recovery handling. Additionally the Harbour
Error Object supports and properties, which allows error handlers to perform some preparations, and then request a
Retry Operation, a
Resume, or return a
Value to replace the expression triggering the error condition. Alternatively statements are available on
xhb library working like the construct.
Procedures and functions [STATIC] PROCEDURE
SomeProcedureName [STATIC] PROCEDURE
SomeProcedureName() [STATIC] PROCEDURE
SomeProcedureName(
Param1 [,
ParamsN] ) INIT PROCEDURE
SomeProcedureName EXIT PROCEDURE
SomeProcedureName [STATIC] FUNCTION
SomeProcedureName [STATIC] FUNCTION
SomeProcedureName() [STATIC] FUNCTION
SomeProcedureName(
Param1 [,
ParamsN] )
Procedures and
functions in Harbour can be specified with the
keywords PROCEDURE, or FUNCTION. Naming rules are the same as those for
Variables (up to 63 characters non-case sensitive). Both Procedures and Functions may be qualified by the scope qualifier
STATIC to restrict their usage to the scope of the module where defined. The
INIT or
EXIT optional qualifiers, will flag the procedure to be automatically invoked just before calling the application startup procedure, or just after quitting the application, respectively.
Parameters passed to a procedure/function appear in the subroutine as local variables, and may accept any type, including references. Changes to argument variables are not reflected in respective variables passed by the calling procedure/function/method unless explicitly passed BY REFERENCE using the
@ prefix. PROCEDURE has no return value, and if used in an Expression context will produce a
NIL value. FUNCTION may return any type by means of the RETURN statement, anywhere in the body of its definition. An example procedure definition and a function call follows: x := Cube( 2 ) FUNCTION Cube( n ) RETURN n ** 3
Sample code The typical "
hello world" program would be: ? "Hello, world!" Or: QOut( "Hello, world!" ) Or: Alert( "Hello, world!" ) Or, enclosed in an explicit procedure: PROCEDURE Main() ? "Hello, world!" RETURN
OOP examples Main procedure: #include "hbclass.ch" PROCEDURE Main() LOCAL oPerson CLS oPerson := Person():New( "Dave" ) oPerson:Eyes := "Invalid" oPerson:Eyes := "Blue" Alert( oPerson:Describe() ) RETURN Class definition: CREATE CLASS Person VAR Name INIT "" METHOD New( cName ) METHOD Describe() ACCESS Eyes INLINE ::pvtEyes ASSIGN Eyes( x ) INLINE iif( HB_ISSTRING( x ) .AND. x $ "Blue,Brown,Green", ::pvtEyes := x, Alert( "Invalid value" ) ) PROTECTED: VAR pvtEyes ENDCLASS // Sample of normal Method definition METHOD New( cName ) CLASS Person ::Name := cName RETURN Self METHOD Describe() CLASS Person LOCAL cDescription IF Empty( ::Name ) cDescription := "I have no name yet." ELSE cDescription := "My name is: " + ::Name + ";" ENDIF IF ! Empty( ::Eyes ) cDescription += "my eyes' color is: " + ::Eyes ENDIF RETURN cDescription ==Tools==