EXTEND CLASS...WITH METHOD
Adds a new method to an existing class.
Syntax
EXTEND CLASS <ClassName> WITH ;
[ MESSAGE <MessageName>] METHOD <FunctionName>
or
EXTEND CLASS <ClassName> WITH ;
MESSAGE <MessageName> INLINE <expression>
Arguments
<ClassName>
This is the symbolic name of an existing class to add a new method to.
MESSAGE <MessageName>
This is the symbolic name of the message which invokes the new method.
METHOD <FunctionName>
This is the symbolic name of the function implementing the code for the new method. If
<MessageName> is omitted, <FunctionName> defines also the message that must be sent to an object for invoking the method.
INLINE <expression>
This is the expression which is executed when an INLINE method is invoked. <expression>
must be one line of code. The code cannot contain commands but only function and method calls.
Description
The EXTEND CLASS...WITH METHOD statement allows for adding new methods to a declared class outside the class declaration. This way, a class can be enhanced even if the source code of the class is not available. The EXTEND CLASS statemend can modify all classes existing in xHarbour.
The new method is either implemented as aSTATIC FUNCTIONor as an INLINE expression. The self object is retrieved in both cases with functionHB_QSelf().
Note: an alternative for enhancing an existing class is to use the FROM option of theCLASSstatement and create a sub-class of an existing class.
EXTEND CLASS...WITH METHOD
Info
See also: ASSOCIATE CLASS,CLASS,EXTEND CLASS...WITH DATA,HB_QSelf(), METHOD...OPERATOR,OPERATOR,OVERRIDE METHOD
Category: Class declaration,Declaration,xHarbour extensions Header: hbclass.ch
Source: vm\classes.c
LIB: xhb.lib
DLL: xhbdll.dll
Example
// The example adds a method to the "root" class of xHarbour: HBObject().
// All new classes inherit from this class. This is used in the example // for tracing variables depending on their data types in different log // files.
#include "HbClass.ch"
PROCEDURE Main
LOCAL obj, nValue := 2, dDate := Date()
EXTEND CLASS HBObject WITH MESSAGE log METHOD LogData ENABLE TYPE CLASS ALL
obj := Test():new( "xHarbour" ) obj:log( "Objects.log" )
nValue:log( "Numerics.log" ) dDate:log( "Dates.log" ) RETURN
CLASS Test EXPORTED:
DATA value
METHOD init(x) INLINE (::value := x, self) ENDCLASS
STATIC FUNCTION LogData( cLogFile ) LOCAL self := HB_QSelf()
LOCAL cOldFile
IF .NOT. Set( _SET_TRACE ) RETURN self
ENDIF
IF Valtype( cLogFile ) == "C"
cOldFile := Set( _SET_TRACEFILE, cLogFile ) ENDIF
Tracelog( self ) IF cOldFile <> NIL
Set( _SET_TRACEFILE, cOldFile ) ENDIF
RETURN self
EXTERNAL
EXTERNAL
Declares the symbolic name of an external function or procedure for the linker.
Syntax
EXTERNAL <name1> [,<nameN>]
Arguments
EXTERNAL <name>
This is the symbolic name of a function or procedure to declare for the linker. When multiple names are declared, they must be separated with commas.
Description
The EXTERNAL statement declares a symbolic name of a function or procedure for the linker. This is usually required when there is no direct call of a function or procedure in PRG code, for example when a function is only called within a macro-expression using the macro-operator. By declaring the
symbolic name of a function as EXTERNAL, the linker is forced to link the corresponding function to the executable file.
Note: It is common practice to use the EXTERNAL declaration within an #include file. This way it is assured that functions are available in all PRG files that may call them indirectly.
Info
See also: #include,ANNOUNCE,REQUEST Category: Declaration,Statements
Example
// The example forces the linker to link three functions that are only // called within a macro expression.
EXTERNAL Memoedit, Memoread, Memowrit MEMVAR fileName
STATIC cEditor := "Memowrit(fileName,Memoedit(Memoread(fileName)))"
PROCEDURE Main( cFile ) fileName := cFile
&cEditor RETURN
FIELD
FIELD
Declares a field variable
Syntax
FIELD <fieldName,...> [IN <aliasName>]
Arguments
FIELD <fieldNames,...>
This is a comma separated list of symbolic names identifying field variables.
IN <aliasName>
Optionally, the alias name of the work area that holds field variables can be specified.
Description
The FIELD statement declares symbolic names of variables whose values are stored in database files.
This instructs the compiler to resolve unaliased variable names to field variables, not memory
variables. All variables listed in <fieldNames,...> that appear in program code without alias name and alias operator, are treated as if they are listed with the FIELD-> alias name, or the one specified with the IN clause.
The FIELD statement does not verify if the field variables exist at runtime or if a database is open with
<aliasName> as name. When the declared field variable does not exist at runtime, an error is generated.
The scope of the FIELD variable depends on the place of declaration:
1. When the FIELD declaration appears at the top of a PRG file before any other executable statement, the declaration has file wide scope, i.e. it is valid throughout the entire PRG file.
2. When the FIELD declaration follows a FUNCTION, METHOD or PROCEDURE declaration, the variable is treated as FIELD variable only in the routine that declares the FIELD.
The lines in PRG source code preceding the FIELD declaration may not call executable code. They can only contain declaration statements, i.e. only the FUNCTION, METHOD, PROCEDURE statements, and the LOCAL, MEMVAR, PARAMETERS, or STATIC variable declarations are allowed to precede the FIELD statement.
Info
See also: FUNCTION,GLOBAL,LOCAL,MEMVAR,PROCEDURE,STATIC Category: Declaration,Statements
Example
PROCEDURE Main
FIELD InvoiceNo, AmountDue, Payment IN Inv FIELD CustNo , FirstName, LastName IN Cust USE Customer ALIAS Cust SHARED
INDEX ON CustNo TO CustA
USE Invoice ALIAS Inv SHARED NEW SET RELATION TO CustNo INTO Cust
FIELD GO TOP
SET ALTERNATE TO NotPaid.txt SET ALTERNATE ON
DO WHILE .NOT. Eof() IF Payment == 0
? CustNo, Lastname, FirstName, InvoiceNo, AmountDue ENDIF
SKIP ENDDO
SET ALTERNATE TO DbCloseAll() RETURN
FOR
FOR
Executes a block of statements a specific number of times.
Syntax
FOR <nCounter> := <nStart> TO <nEnd> [STEP <nIncrement>]
<Statements>
FOR <nCounter> := <nStart>
<nCounter> is the name of the variable that holds a counter value used to control the number of iterations of the FOR...NEXT loop. If <nCounter> does not exist when the loop is entered, it is created as a PRIVATE variable. The value <nStart> is a numeric start value to initialize
<nCounter> with when the FOR statement is executed for the first time.
TO <nEnd>
<nEnd> is a numeric value that controls the termination of the FOR...NEXT loop. As soon as
<nCounter> is greater than or equal to <nEnd>, the statements between FOR and NEXT are no longer executed.
STEP <nIncrement>
<nIncrement> is a numeric value <nCounter> is incremented with for each iteration of the loop.
If not specified, it defaults to 1. When <nIncrement> is a negative value, the loop ends when
<nCounter> is smaller than or equal to <nEnd>.
EXIT
The EXIT statement unconditionally terminates a FOR...NEXT loop. Program flow branches to the first statement following the NEXT statement.
LOOP
The LOOP statement branches control unconditionally to the FOR statement, i.e. to the begin of the loop.
Description
The FOR...NEXT statements form a control structure that executes a block of statements for a specific number of times. This is controlled by the <nCounter> counter variable which gets assigned the value
<nStart> when the loop is entered for the first time. The loop iterates the statements between FOR and NEXT and adds the value <nIncrement> to <nCounter> each time the NEXT statement is reached or a LOOP statement is executed.
The value <nEnd> identifies the largest value for <nCounter> (<nIncrement> is positive) or its smallest value (<nIncrement> is negative) after which the FOR...NEXT loop terminates.
Note: The expressions in the FOR statement are evaluated each time a new iteration begins. As a consequence, new values can be assigned to <nCounter> or <nEnd> while the loop executes.
FOR
Info
See also: AEval(),FOR EACH,DO CASE,DO WHILE,IF,SWITCH,WITH OBJECT Category: Control structures,Statements
Example
// This example shows a typical scenario for a FOR..NEXT loop // where an array is filled with data, and stored data is output.
PROCEDURE Main LOCAL aFields, i USE Customer
aFields := Array( FCount() ) // fill array in regular order FOR i:=1 TO FCount()
aArray[i] := FieldName(i) NEXT
USE
// output data in reverse order FOR i:=Len( aArray ) TO 1 STEP -1
? aArray[i]
NEXT RETURN