DO

DO*

Call a procedure

Syntax

      DO <idProcedure> [WITH <argument list>]

Arguments

<idProcedure> is the name of the procedure or user-defined function to be executed.

WITH <argument list> specifies up to 128 arguments, separated by commas, to pass to <idProcedure>. Each argument may be a single variable, field, array, array element, expression, or object. Arguments can be skipped or left off the end of the list.

Description

The DO statement calls a procedure or user-defined function, optionally passing arguments to the called routine. It performs the same action as a user-defined function or procedure specified on a line by itself with the exception that variables other than field variables are passed by reference as the default. In order to pass a field variable as an argument, enclose it in parentheses, unless you declare it with the FIELD statement or with an alias.

The number of specified arguments need not match the number of specified parameters in the called procedure. If the number of arguments is less than the number of parameters, the parameter variables with no corresponding arguments are initialized with a NIL value when the procedure is called. If the number of arguments is greater than the number of parameters, they are ignored.

Also, skipping an argument within the <argument list> by leaving an empty spot next to the comma initializes the corresponding argument to NIL. To detect the position of the last argument passed in the <argument list>, use PCOUNT(). To detect a skipped argument, compare the receiving parameter to NIL.

In addition to calling a procedure or user-defined function, DO also has an effect on compilation if you compile the current program file without the /M option. If the compiler encounters a DO statement and the specified procedure has not already been compiled, the compiler searches the current directory for a .prg file with the same name and compiles it. If the file with the same name as the procedure is not found, the called procedure is assumed to be external, and a reference is added to the object (.OBJ) file. At link time, the linker will search other object files and libraries for this external reference.

DO is a compatibility statement and therefore not recommended. Calling a procedure or function on a line by itself is the preferred method. Since this preferred calling convention normally passes parameters by value, you must preface an argument with the pass- by-reference operator (@) in order to pass by reference. If you are using DO to make a procedure call more readable, a user-defined command, specified with the #command directive, can provide greater readability without sacrificing the safety of variables passed as parameters. For more information on passing parameters refer to the Functions and Procedures section of the “Basic Concepts”.

Examples

       .  This example executes a procedure with no parameters:
          DO AcctsRpt
          AcctsRpt()                           // Preferred method
       .  This example executes a procedure passing two constants:
          DO QtrRpt WITH "2nd", "Sales Division"
          QtrRpt("2nd", "Sales Division")      // Preferred method
       .  In this example, a procedure is executed with the first
          argument passed by value and the second passed by reference:
          nNumber := 12
          DO YearRpt WITH nNumber + 12, nNumber
          YearRpt(nNumber + 12, @nNumber)      // Preferred method
       .  Here, a procedure is invoked with skipped arguments embedded
          in the list of arguments:
          DO DisplayWindow WITH ,,,,"My Window"
          DisplayWindow(,,,,"My Window")       // Preferred method

Seealso

FUNCTION, LOCAL, PARAMETERS, PRIVATE, PROCEDURE, PUBLIC

PARAMETERS

PARAMETERS

Declares private parameter variables

Syntax

PARAMETERS <idPrivate list>

Arguments

<idPrivate list> is one or more parameter variables separated by commas.

The number of receiving variables does not have to match the number of arguments passed by the calling procedure or user-defined function.

Description

The PARAMETERS statement declares private variables to receive passed values or references. Receiving variables are referred to as parameters. The values or references actually passed by a procedure or user-defined function invocation are referred to as arguments.

When a PARAMETERS statement executes, all variables in the parameter list are created as private variables and all public or private variables with the same names are hidden until the current procedure or user-defined function terminates. A PARAMETERS statement is an executable statement and, therefore, can occur anywhere in a procedure or user-defined function, but must follow all compile-time variable declarations, such as FIELD, LOCAL, MEMVAR, and STATIC.

Parameters can also be declared as local variables if specified as a part of the PROCEDURE or FUNCTION declaration statement (see the example). Parameters specified in this way are referred to as formal parameters. Note that you cannot specify both formal parameters and a PARAMETERS statement with a procedure or user-defined function definition. Attempting to do this results in a fatal compiler error and an object file is not generated.

In Harbour the number of arguments and parameters do not have to match. If you specify more arguments than parameters, the extra arguments are ignored. If you specify fewer arguments than parameters, the extra parameters are created with a NIL value. If you skip an argument, the corresponding parameter is initialized to NIL. The PCOUNT() function returns the position of the last argument passed in the list of arguments. This is different from the number of parameters passed since it includes skipped parameters.

Examples

     .  This user-defined function receives values passed into private
        parameters with a PARAMETERS statement:

        FUNCTION MyFunc
           PARAMETERS cOne, cTwo, cThree
           ? cOne, cTwo, cThree
           RETURN NIL

     .  This example is similar, but receives values passed into local
        variables by declaring the parameter variables within the FUNCTION
        declaration:

        FUNCTION MyFunc( cOne, cTwo, cThree )
           ? cOne, cTwo, cThree
           RETURN NIL

See Also

 FUNCTION, LOCAL, PCOUNT(), PRIVATE, PROCEDURE, STATIC

MEMVAR

MEMVAR

Declares private and public variables and arrays.

Syntax

      MEMVAR <xVar>

Arguments

<xVar> Memory variable Name

Description

This command tells the compiler to resolve any reference to a memory variable designated within this list s if it possessed an explicit memory variable alias with either the M-> or MEMVAR-> prefix.Only those memory variables that do not contain any such explicit are affected by this command. Those memory variabls within macro expansions are not affected by this command.

The MEMVAR declaration must apear before any executable commands;it is similat to the LOCAL, STATIC, FIELD, PARAMETERS, FUNCTION, and PROCEDURE commands statements.

Examples

      MEMVAR y AS NUMERIC
      PROCEDURE Main()
         LOCAL n, lVar

         n := iif( lVar, "A", 3 )
         n := 2
         n := "a"
         n := seconds() + 2
         n := int( seconds() + 2 )
         y := n
         ? y
         RETURN

Tests

      See tests/testwarn.prg for more examples

Compliance

Clipper

Platforms

All

Files

None.

Seealso

LOCAL, STATIC, FIELD, PRIVATE, PUBLIC

LOCAL

LOCAL

Initializes a local memory variable or array

Syntax

      LOCAL <xVar> [:= <xInit> ]

Arguments

<xVar> Name of a memory variable or array.

<xInit> Value to be assinged to a variable or array

Description

This command created a LOCAL memory variable or array. The name of either is specified in <xVar>. If more then one variable is being initialized with the LOCAL command, separate each entry with a comma. If a variable or an array is to be assingned a start-up value, that expression may be specified in <xInit> and folling. Is Strong type compile mode is used, the Compiler will check if the value recived matchs the type specified in <xType>.

LOCAL varibles are symbols generated at run time and are resolved at compile time. The visibility and life span of a LOCAL variable or array is limited to the function or procedure in which it is defined.

No macro expansions are allowed in the LOCAL declaration statement.

No Harbour command other then FUNCTION, PROCEDURE, PUBLIC, PRIVATE, PARAMETERS, MEMVAR, STATIC and FIELD, may precede the LOCAL command.

LOCAL array reference may not be initialized (i.e., assigned values) on the same command line as the LOCAL command statement. This can be done later in the program.

LOCAL variables and arrays are not affected by the RELEASE command.

Examples

      PROCEDURE Main()
         LOCAL n, lVar

         n := iif( lVar, "A", 3 )
         n := 2
         n := "a"
         n := seconds() + 2
         n := int( seconds() + 2 )
         RETURN

Tests

      See tests/testwarn.prg for more examples

Compliance

Clipper

Platforms

All

Files

None

Seealso

FIELD, PRIVATE, PUBLIC, STATIC, MEMVAR

Codeblocks

The Harbour implementation of codeblocks

Author : Ryszard Glab <rglab@imid.med.pl>

Compilation of a codeblock.
During compile time the codeblock is stored in the following form:
- the header
- the stream of pcode bytes
The header stores information about referenced local variables.
+0: the pcode byte for _PUSHBLOCK
+1: the number of bytes that defines a codeblock
+3: number of codeblock parameters (declared between || in a codeblock)
+5: number of used local variables declared in procedure/function where
 the codeblock is created
+7: the list of procedure/function local variables positions on the eval
 stack of procedure/function. Every local variable used in a codeblock
 occupies 2 bytes in this list. When nested codeblocks are used then this
 list is created for the outermost codeblock only.
+x: The stream of pcode bytes follows the header.
+y: the pcode byte for _ENDBLOCK

Creation of a codeblock.
When HB_P_PUSHBLOCK opcode is executed then the HB_ITEM structure is created
and placed on the eval stack. The type of item is IT_BLOCK. The value of this
item is a pointer to HB_CODEBLOCK structure. Additionally this item stores the
base of static variables defined for the current function/procedure - this
is used during a codeblock evaluation when the evaluation is called from a code
from other PRG module. Also the number of expected parameters is stored.
The HB_CODEBLOCK structure stores a pointer to the pcodes stream that is
executed during a codeblock evaluation. It stores also the pointer to a table
with local variables references. Values of all local variables defined in a
procedure and used in a codeblock are replaced with a reference to a
value stored in a global memory variables pool. This allows the correct access
to detached local variables in a codeblock returned from this function (either
directly in RETURN statement or indirectly by assigning it to a static or
memvar variable. This automatic and unconditional replace is required because
there is no safe method to find if a codeblock will be accessed from an outside
of a function where it is created.
When nested codeblocks are used then only the outermost codeblock creates
the table - all inner codeblock uses this table. The first element of this
table contains a reference counter for this table. It allows to share the table
between nested codeblock - the table is deleted if there is no more references
to it. This is caused by the fact that a inner codeblock can be created during
evaluation of outer codeblock when local variables don't exist like in this
example:
PROCEDUE Main()
 PRIVATE foo, bar
Test()
 Eval( foo )
 Eval( bar )

PROCEDURE Test()
 LOCAL a := "FOO", b := "BAR"
foo := {|| a + ( bar := Eval( {|| b } ) ) }
RETURN

Evaluation of a codeblock.
Parameters passed to a codeblock are placed on the eval stack before a
codeblock evaluation. They are accessed just like usual function
parameters. When a codeblock parameter is referenced then its position on the
eval stack is used. When a procedure local variable is referenced then the
index into the table of local variables positions (copied from the header) is
used. The negative value is used as an index to distinguish it from the
reference to a codeblock parameter.

Incompatbility with the Clipper.
1) Detached locals passed by reference
There is a little difference between the handling of variables passed by
the reference in a codeblock.
The following code explains it (thanks to David G. Holm)
PROCEDURE Main()
 LOCAL nTest
 LOCAL bBlock1 := MakeBlock()
 LOCAL bBlock2 := {|| DoThing( @nTest ), QOut( "From Main: ", nTest ) }
Eval( bBlock1 )
 Eval( bBlock2 )
RETURN
FUNCTION MakeBlock()
 LOCAL nTest
 RETURN {|| DoThing( @nTest ), QOut( "From MakeBlock: ", nTest ) }
FUNCTION DoThing( n )
n := 42
RETURN NIL

 In Clipper it produces:
From MakeBlock: NIL
From Main: 42
In Harbour it produces (it is the correct output, IMHO)
From MakeBlock: 42
From Main: 42

2) Scope of undeclared variables
 Consider the following code:
PROCEDURE Main()
 LOCAL cb
 cb := Detach()
 ? Eval( cb, 10 )
 RETURN
FUNCTION Detach()
 LOCAL b := {| x | x + a }
 LOCAL a := 0
 RETURN b

In Clipper the 'a' variable in a codeblock has the *local* scope however in
Harbour the 'a' variable has the *private* scope. As a result, in Clipper
this code will print 10 and in Harbour it will raise 'argument error' in
'+' operation.
 This will be true also when the 'a' variable will be declared as PRIVATE

PROCEDURE Main()
 LOCAL cb
 PRIVATE a
 cb := Detach()
 ? Eval( cb, 10 )
 RETURN

The above code also prints 10 in Clipper (even if compiled with -a or -v
switches)

Source : https://github.com/harbour/core/blob/master/doc/codebloc.txt

C5_LOCAL

LOCAL
 Declare and initialize local variables and arrays
------------------------------------------------------------------------------
 Syntax

     LOCAL <identifier> [[:= <initializer>], ... ]

 Arguments

     <identifier> is the name of a variable or array to declare local.
     If the <identifier> is followed by square brackets ([ ]), it is created
     as an array.  If the <identifier> is an array, the syntax for specifying
     the number of elements for each dimension can be array[<nElements>,
     <nElements2>,...] or array[<nElements>][<nElements2>]...  The maximum
     number of elements per dimension is 4096.  The maximum number of
     dimensions per array is limited only by available memory.

     <initializer> is the optional assignment of a value to a new local
     variable.  Array identifiers, however, cannot be given values with an
     <initializer>.  An <initializer> for a local variable consists of the
     inline assignment operator (:=) followed by any valid Clipper
     expression including a literal array.  If no explicit <initializer> is
     specified, the variable is given an initial value of NIL.  In the case
     of an array, each element is NIL.

     Note:  The macro operator (&) cannot be used in a LOCAL declaration
     statement.

 Description

     LOCAL is a declaration statement that declares one or more variables or
     arrays local to the current procedure or user-defined function, and must
     occur before any executable statement including PRIVATE, PUBLIC, and
     PARAMETERS.  Local variable declarations hide all inherited private
     variables and visible public variables with the same name.  A LOCAL
     statement, however, that declares a variable name which is already
     declared causes a fatal compiler error and no object file (.OBJ) is
     generated.  This error can happen as a result of two declarations for
     the same variable name in the same routine, or as the result of
     redeclaring a variable with filewide scope.  Declaration statements
     include FIELD, MEMVAR, and STATIC.

     Local variables are visible only within the current procedure or user-
     defined function and, unlike private variables, are not visible within
     invoked routines.  Local variables are created automatically each time
     the procedure in which they were declared begins executing.  They
     continue to exist and retain their values until the declaring procedure
     or user-defined function returns control to the code that invoked it.
     If a procedure or user-defined function is invoked recursively (calls
     itself), each recursive activation creates a new set of local variables.

     The initial value of local variables and array elements is NIL if not
     explicitly initialized, either in the initializer list or by assignment.
     The initializer expression can be any valid Clipper expression,
     including function calls.  Note that an array declaration cannot have an
     initializer.

     The maximum number of local variables in a program is limited only by
     available memory.  Arrays, however, assigned to a local variable are
     still limited to 4096 elements per dimension.

     For more information on variable declarations and scoping, refer to the
     Variables section in the "Basic Concepts" chapter of the Programming and
     Utilities Guide.

 Notes

     .  Inspecting local variables within the debugger: To access
        local variable names within the Clipper DOS-level debugger, you
        must compile program (.prg) files using the /B option so that local
        variable information is included in the object file.

     .  Local parameters: Declare a list of local parameters as a part
        of a FUNCTION or PROCEDURE declaration by enclosing the list of
        parameters in parentheses following the <idFunction>:

        FUNCTION <idFunction>(<idParam list>)

        Declaration of local parameters supersedes creation of private
        parameters with the PARAMETERS statement.

     .  Macro expressions: You cannot refer to local variables within
        macro variables and expressions.  If you refer to a local variable
        within a macro variable, a private or public variable with the same
        name will be referenced instead.  If no such variable exists, a
        runtime error will be generated.

     .  Memory files: Local variables cannot be SAVED to or RESTOREd
        from memory (.mem) files.

     .  Type of a local variable: Since TYPE() uses the macro operator
        (&) to evaluate its argument, it cannot be used to determine the type
        of a local or static variable or an expression containing a local or
        static variable reference.  The VALTYPE() function provides this
        facility.  VALTYPE() evaluates its argument and returns the type of
        the return value.

 Examples

     .  This example declares two local arrays and two local
        variables:

        LOCAL aArray1[20, 10], aArray2[20][10], var1, var2

     .  This example declares two local variables with initializers.
        The first is initialized to a date value and the second to a literal
        array:

        LOCAL dWhen := DATE()
        LOCAL aVegies := {"Tomato", "Chickadee", "Butterbean"}

See Also: FUNCTION PARAMETERS PRIVATE PROCEDURE PUBLIC STATIC

 

[ ] Array element indicator

 


 [ ]
 Array element indicator                         (Special)
------------------------------------------------------------------------------
 Syntax

     <aArray>[<nSubscript>, ... ]
     <aArray>[<nSubscript1>][<nSubscript2>] ...

 Operands

     <aArray> is an expression that returns a reference to an array.
     This is generally a variable identifier or instance variable.

     <nSubscript> is a numeric expression that addresses an individual
     element in the specified array or subarray.  Each subscript corresponds
     to a dimension of the array.

 Description

     The subscript operator ([]) specifies a single array element.  The name
     of a previously declared array must precede the left bracket and the
     array element subscript must appear as a numeric expression within the
     brackets.  You can make array element references using Pascal or C-style
     syntax.

 Examples

     .  This example accesses each element in a two-dimensional array
        of known dimensions:

        LOCAL i, j
        FOR i := 1 TO 5
           FOR j := 1 TO 10
              ? aOne[i, j]
           NEXT
        NEXT

     .  These examples specify an <aArray> expression:

        LOCAL aArray := { 1, 2, 3, 4, 5 }
        //
        ? ArrayFunc()[2]                     // Result: 2
        ? { {1, 2}, {3, 4} }[1][2]           // Result: 2
        ? aArray[5]                          // Result: 5

        FUNCTION ArrayFunc
           STATIC aArray := { 1, 2 }
           RETURN aArray

     .  This example queries and assigns a static array encapsulated
        within a function definition:

        ? ArrayFunc()[1]                     // Result: 1
        ArrayFunc()[1] := 10
        ? ArrayFunc()[1]                     // Result: 10

        FUNCTION ArrayFunc
           STATIC aArray := { 1, 2 }
           RETURN aArray

See Also: ARRAY() LOCAL PRIVATE PUBLIC STATIC

Array Basics

    An array is a distinct data type which may contains multiple data items under same name.  Data items stored in an array referred as an “element” and can be any data type. An individual element of array referenced by array name and position number of element as an integer in array, called “index” or “subscript”.

 Defining / Building:

    An array is a variable and like all variables has “scope”; arrays can be defined PRIVATE, PUBLIC and LOCAL as well as STATIC.

   Building an array is quite simple: for example to define an array named “aColors” with 5 elements we can use a statement like this:

LOCAL aColors[ 5 ]

or

LOCAL aColors := ARRAY( 5 )

or

LOCAL  aColors := {  , , , , }

Results of these three methods are exactly same; we can inspect easily:

? ValType( aColors )      // A

? LEN( aColors )          // 5
? HB_ValToExp( aColors )  // {NIL, NIL, NIL, NIL, NIL}

NIL is a special data type with meaning “not defined”.

We can define an array with initial value(s)

aColors := {  “green”, ”yellow” ,  “red”,  “black”, “white” }

or assign values after defined:

aColors[ 1 ] := ”green”
aColors[ 2 ] := ”yellow”
aColors[ 3 ] := ”red”
aColors[ 4 ] := ”black”
aColors[ 5 ] := ”white”
? HB_ValToExp( aColors ) // {"green", "yellow", "red", "black", "white"}

Retrieve:

As seen in our first array statement

LOCAL aColors[ 5 ]

used a special sign square brackets as “Array element indicator” ( used also as string delimiter ).

As cited at the beginning, an individual element of array is referenced by array name and position number of element as an integer (enclosed by square brackets) in array, called “index” or “subscript”, and this notation called “subscripting”.

Note that subscribing begins with one.

To specify more than one subscript ( i.e. when using multi-dimensional arrays), you can either enclose each subscript in a separate set of square brackets, or separate the subscripts with commas and enclose the list in square brackets. For example, if aArray is a two dimensional array, the following statements both addresses the second column element of tenth row:

aArray[ 10 ][ 2]
aArray[ 10, 2]

Of course it’s illegal to address an element that is outside of the boundaries of the array (lesser than one or greater than array size / length; one is also illegal for an empty array). Attempting to do so will result in a runtime error.

When making reference to an array element using a subscript, you are actually applying the subscript operator ([]) to an array expression, not only an array identifier (array variable name). An array expression is any valid expression that evaluate to an array. This includes function calls, variable references, subscripting operations, or any other expression that evaluate to an array. For example, the following are all valid:

 { “a”, “b”, “c” }[ 2 ]

x[ 2 ]
ARRAY(3)[ 2 ]
&(<macro expression>)[ 2 ]
(<complex expression>)[ 2 ]

Syntax :

 <aArrayName> [ <nSubscript> ]

<nSubscript> is integer value and indicate sequence number of element into this array.

With this way we can also traverse an array:

FOR nColor := 1 TO LEN( aColors )
     ? aColors[ nColor ]
NEXT nColor

In fact, with the other FOR loop, traversing an array doesn’t require subscripting:

cColor := “” // FOR EACH loop require a predefined loop element

FOR EACH cColor IN aColors
  ? cColor
NEXT nColor

Elements of an array may be different data type; thus arrays called as “ragged” arrays in Clipper language.

aRagged := { 1, "One", DATE(),  .T. } 
FOR nIndex := 1 TO LEN( aRagged )
   x1Elem := aRagged[ nIndex  ]
   ? VALTYPE( x1Elem ), x1Elem
NEXT nIndex

A build-in array function AEVAL() can be use instead of a loop :

AEVAL( aRagged, { | x1 | QOUT(x1 ) } )

 

Adding one element to end of an array:

The architect of array is quite versatile. Array may change ( in size and element values ) dynamically at run time.

 AADD() function can be used for add a new element to the end of an array

AADD(<aTarget>, <expValue>) --> Value

<aTarget> is the array to which a new element is to be added.

<expValue> is the value assigned to the new element.

AADD() is an array function that increases the actual length of the target array by one.  The newly created array element is assigned the value specified by <expValue>.

AADD() is used to dynamically grow an array.  It is useful for building dynamic lists or queues.

For example an array may build empty and later add element(s) to it :

aColors := {}
AADD( aColors, ”green” )
AADD( aColors, ”yellow” )
AADD( aColors, ”red” )
AADD( aColors, ”black” )
AADD( aColors, ”white” )
? HB_ValToExp( aColors ) // {"green", "yellow", "red", "black", "white"}
Inserting one element to an array:

AINS() function can be use for insert a NIL element into an array

AINS (<aTarget>, <nPosition>) --> aTarget

<aTarget> is the array into which a new element will be inserted.

<nPosition> is the position at which the new element will be  inserted.

AINS() is an array function that inserts a new element into a specified array.  The newly inserted element is NIL data type until a new value is assigned to it.  After the insertion, the last element in the array is discarded, and all elements after the new element are shifted down one position.

For a lossless AINS() ( HL_AINS() ) look at attached .prg.

Deleting one element from an array:

ADEL(<aTarget>, <nPosition>) --> aTarget

ADEL() is an array function that deletes an element from an array.  The content of the specified array element is lost, and all elements from that position to the end of the array are shifted up one element.  The last element in the array becomes NIL. So, ADEL() function doesn’t change size of array.

For an another ADEL()  ( HL_ADEL() ) look at attached .prg.

Resizing:

 ASIZE() function can be use for grow or shrink, that is changing size of an array.

ASIZE( <aTarget>, <nLength>) --> aTarget

<aTarget> is the array to grow or shrink.

<nLength> is the new size of the array.

 

     ASIZE() is an array function that changes the actual length of the   <aTarget> array.  The array is shortened or lengthened to match the specified length.  If the array is shortened, elements at the end of the array are lost.  If the array is lengthened, new elements are added to the end of the array and assigned NIL.

     ASIZE() is similar to AADD() which adds a single new element to the end   of an array and optionally assigns a new value at the same time.  Note that ASIZE() is different from AINS() and ADEL(), which do not actually      change the array’s length.

Assigning a fixed value to all elements of an array:

Changing values of all element of an array can not be accomplish by a simple assign statement. For example:

aTest := ARRAY( 3 )
aTest := 1

change type of aTest from array to numeric with a value 1.

Instead, AFILL() function gives a short way to fill an array with a fixed value.

AFILL() :  Fill an array with a specified value

Syntax :

AFILL(<aTarget>, <expValue>,
    [<nStart>], [<nCount>]) --> aTarget
    <aTarget> is the array to be filled.

<expValue> is the value to be placed in each array element.  It can be an expression of any valid data type.

<nStart> is the position of the first element to be filled.  If this argument is omitted, the default value is one.

<nCount> is the number of elements to be filled starting with  element <nStart>.  If this argument is omitted, elements are filled from the starting element position to the end of the array.

Code evaluation on an array:

AEVAL()

Execute a code block for each element in an array

Syntax:

AEVAL(<aArray>, <bBlock>,
    [<nStart>], [<nCount>]) --> aArray

Arguments:

<aArray> is the array to traverse.

<bBlock> is a code block to execute for each element encountered.

<nStart> is the starting element.  If not specified, the default is  element one.

<nCount> is the number of elements to process from <nStart>.  If not specified, the default is all elements to the end of the array.

Returns:

     AEVAL() returns a reference to <aArray>.

Description:

AEVAL() is an array function that evaluates a code block once for each element of an array, passing the element value and the element index as  block parameters.  The return value of the block is ignored.  All      elements in <aArray> are processed unless either the <nStart> or the  <nCount> argument is specified.

AEVAL() makes no assumptions about the contents of the array elements it is passing to the block.  It is assumed that the supplied block knows  what type of data will be in each element.

AEVAL() is similar to DBEVAL() which applies a block to each record of a  database file.  Like DBEVAL(), AEVAL() can be used as a primitive for  the construction of iteration commands for both simple and complex array  structures.

Refer to the Code Blocks section in the “Basic Concepts” chapter of the   Programming and Utilities Guide for more information on the theory and syntax of code blocks.

Examples :

This example uses AEVAL() to display an array of file names  and file sizes returned from the DIRECTORY() function:

#include “Directry.ch”

//

LOCAL aFiles := DIRECTORY(“*.dbf”), nTotal := 0

AEVAL(aFiles, { | aDbfFile |;
     QOUT( PADR(aDbfFile[F_NAME], 10), aDbfFile[F_SIZE]),;
     nTotal += aDbfFile[F_SIZE])} )
//
?
? "Total Bytes:", nTotal

This example uses AEVAL() to build a list consisting of  selected items from a multi-dimensional array:

#include "Directry.ch"
//
LOCAL aFiles := DIRECTORY("*.dbf"), aNames := {}
AEVAL(aFiles, { | file | AADD(aNames, file[F_NAME]) } )

This example changes the contents of the array element depending on a condition.  Notice the use of the codeblock  parameters:

 

LOCAL aArray[6]
AFILL(aArray,"old")
AEVAL(aArray,;
{|cValue,nIndex| IF( cValue == "old",;
aArray[nIndex] := "new",)})

Searching a value into an array :

ASCAN() : Scan an array for a value or until a block returns true (.T.)

Syntax:

ASCAN(<aTarget>, <expSearch>,
       [<nStart>], [<nCount>]) --> nStoppedAt

 Arguments:

<aTarget> is the array to be scanned.

<expSearch> is either a simple value to scan for, or a code block.   If <expSearch> is a simple value it can be character, date, logical, or  numeric type.

<nStart> is the starting element of the scan.  If this argument is not specified, the default starting position is one.

<nCount> is the number of elements to scan from the starting  position.  If this argument is not specified, all elements from the  starting element to the end of the array are scanned.

 Returns:

ASCAN() returns a numeric value representing the array position of the last element scanned.  If <expSearch> is a simple value, ASCAN() returns the position of the first matching element, or zero if a match is not  found.  If <expSearch> is a code block, ASCAN() returns the position of the element where the block returned true (.T.).

 Description:

ASCAN() is an array function that scans an array for a specified value and operates like SEEK when searching for a simple value.  The  <expSearch> value is compared to the target array element beginning with  the leftmost character in the target element and proceeding until there are no more characters left in <expSearch>.  If there is no match,  ASCAN() proceeds to the next element in the array.

Since ASCAN() uses the equal operator (=) for comparisons, it is  sensitive to the status of EXACT.  If EXACT is ON, the target array  element must be exactly equal to the result of <expSearch> to match.

If the <expSearch> argument is a code block, ASCAN() scans the <aTarget>   array executing the block for each element accessed.  As each element is encountered, ASCAN() passes the element’s value as an argument to the code block, and then performs an EVAL() on the block.  The scanning operation stops when the code block returns true (.T.), or ASCAN()  reaches the last element in the array.

  Examples:

This example demonstrates scanning a three-element array using simple values and a code block as search criteria.  The code block criteria show how to perform a case-insensitive search:

aArray := { "Tom", "Mary", "Sue" }
? ASCAN(aArray, "Mary")               // Result: 2
? ASCAN(aArray, "mary")               // Result: 0
//
? ASCAN(aArray, { |x| UPPER(x) == "MARY" }) // Result: 2

This example demonstrates scanning for multiple instances of a search argument after a match is found:

LOCAL aArray := { "Tom", "Mary", "Sue","Mary" },; 
      nStart := 1
//
// Get last array element position
nAtEnd := LEN(aArray)
DO WHILE (nPos := ASCAN(aArray, "Mary", nStart)) > 0
   ? nPos, aArray[nPos]
   //
   // Get new starting position and test
   // boundary condition
   IF (nStart := ++nPos) > nAtEnd
      EXIT
   ENDIF
ENDDO

This example scans a two-dimensional array using a code block.  Note that the parameter aVal in the code block is an array:

LOCAL aArr:={}
CLS
AADD(aArr,{"one","two"})
AADD(aArr,{"three","four"})
AADD(aArr,{"five","six"})
? ASCAN(aArr, {|aVal| aVal[2] == "four"})         // Returns 2

Sorting an array:

ASORT() :  Sort an array

Syntax:

ASORT(<aTarget>, [<nStart>],
[<nCount>], [<bOrder>]) --> aTarget

 Arguments:

<aTarget> is the array to be sorted.

<nStart> is the first element of the sort.  If not specified, the default starting position is one.

<nCount> is the number of elements to be sorted.  If not specified, all elements in the array beginning with the starting element are sorted.

<bOrder> is an optional code block used to determine sorting order.  If not specified, the default order is ascending.

 Returns:

ASORT() returns a reference to the <aTarget> array.

 Description:

 ASORT() is an array function that sorts all or part of an array  containing elements of a single data type.  Data types that can be  sorted include character, date, logical, and numeric.

If the <bOrder> argument is not specified, the default order is ascending.  Elements with low values are sorted toward the top of the  array (first element), while elements with high values are sorted toward the bottom of the array (last element).

If the <bOrder> block argument is specified, it is used to determine the sorting order.  Each time the block is evaluated; two elements from the target array are passed as block parameters.  The block must return true     (.T.) if the elements are in sorted order.  This facility can be used to create a descending or dictionary order sort.  See the examples below.

When sorted, character strings are ordered in ASCII sequence; logical values are sorted with false (.F.) as the low value; date values are sorted chronologically; and numeric values are sorted by magnitude.

 Notes:

ASORT() is only guaranteed to produce sorted output (as defined by the block), not to preserve any existing natural order in the process.

Because multidimensional arrays are implemented by nesting sub-arrays within other arrays, ASORT() will not directly sort  a multidimensional array.  To sort a nested array, you must supply a code block which properly handles the sub-arrays.

 Examples:

This example creates an array of five unsorted elements, sorts the array in ascending order, then sorts the array in descending  order using a code block:

aArray := { 3, 5, 1, 2, 4 }
ASORT(aArray)
// Result: { 1, 2, 3, 4, 5 }
ASORT(aArray,,, { |x, y| x > y })
// Result: { 5, 4, 3, 2, 1 }

This example sorts an array of character strings in ascending order, independent of case.  It does this by using a code block that  converts the elements to uppercase before they are compared:

aArray := { "Fred", Kate", "ALVIN", "friend" }
ASORT(aArray,,, { |x, y| UPPER(x) < UPPER(y) })

This example sorts a nested array using the second element of each sub-array:

aKids := { {"Mary", 14}, {"Joe", 23}, {"Art", 16} }
aSortKids := ASORT(aKids,,, { |x, y| x[2] < y[2] })

Result:

{ {“Mary”, 14}, {“Art”, 16}, {“Joe”, 23} }

Last element in an array:

ATAIL() : Return the highest numbered element of an array

Syntax:

      ATAIL(<aArray>) --> Element

Arguments:

<aArray> is the array.

 Returns:

ATAIL() returns either a value or a reference to an array or object.  The array is not changed.

 Description:

ATAIL() is an array function that returns the highest numbered element  of an array.  It can be used in applications as shorthand for <aArray>[LEN(<aArray>)] when you need to obtain the last element of an      array.

Examples:

The following example creates a literal array and returns that last element of the array:

     aArray := {"a", "b", "c", "d"}
     ? ATAIL(aArray)                     // Result: d

Getting directory info:

ADIR() is a array function to obtain directory information. But it’s  a compatibility function and therefore not recommended. It is superseded by the DIRECTORY() function which returns all file information in a multidimensional array.

A sample .prg : ArrayBasics.prg 

 

ArrBass

Using code blocks, again

Using code blocks again (.pdf)

The Clipper conversion process

The Clipper conversion process (.pdf)