Sophie

Sophie

distrib > Mageia > 7 > armv7hl > media > core-release > by-pkgid > 5cf9e461dc555a81d748d90a1d732fb9 > files > 42

harbour-3.2.0-3.19676.470.2.mga7.armv7hl.rpm

This document attempts to describe the features separating Harbour from
CA-Cl*pper.

/* TODO: @FunPointer(), and all other Harbour extensions. */

Harbour Macro Compiler
----------------------
The Harbour Macro Compiler offers 2 additional layers of functionality
controlled by means of hb_SetMacro()* function, not available in CA-Cl*pper.

hb_SetMacro( HB_SM_HARBOUR, .T. ) will enable macro compilation and
evaluation of complex expressions not supported by CA-Cl*pper like:

 - exp++, exp--, var += exp, (exp), etc..
 - Nested codeblocks.
 - Expressions longer then 254 characters.

hb_SetMacro( HB_SM_XBASE, .T. ) will enable macro compilation and
evaluation of comma separated lists in all contexts where lists are
acceptable by CA-Cl*pper*, including:

  - { &cMacro } // Literal array elements list.
  - SomeArray[ &cMacro ] // Array index list.
  - SomeFun( &cMacro ) // Arguments list.
  - ( &cMacro ) // parenthesized list expression.

*CA-Cl*pper only supports list macros within codeblocks context.

Both these extra layers are activated by default.

* See also -k Compiler switch.

INIT/EXIT and startup procedures
--------------------------------

In CA-Cl*pper the startup procedure is always the first procedure/function
of the main module, even if such symbol is an INIT or EXIT symbol. In
such case the program will never execute the "main" symbol. In Harbour
the first *non* INIT/EXIT symbol, will be executed as the main symbol
after all INIT procedures have been executed.

FOR EACH statement
------------------
Harbour has support enumeration loop with the following syntax:

   FOR EACH var1 [,var255] IN expr1 [,expr255] [DESCEND]
      [EXIT]
      [LOOP]
      ...
   NEXT

Note:
   - expr can be a string, an array, an hash array or an object with
     custom FOR EACH action
   - enumerator variable 'var<n>' stores a reference to the element of
     an hash, array or a string specified by 'expr<n>' thus assignments
     to the enumerator changes the value of given element of iterated
     item. If FOR EACH is used to iterate string items them assignment
     to enumerator item changes the original string only if it was passed
     to FOR EACH statement by reference, i.e.:
         FOR EACH c IN @string
            IF IsAlpha( c )
               c := Upper( c )
            ELSE
               c := "*"
            ENDIF
         NEXT
   - after the loop the controlling variable(s) restore the value which
     they had before entering the loop
   - the enumerator variable supports the following properties
      :__enumIndex()   - the loop counter for variable
      :__enumKey()     - the hash key value of traversed hash item pair
      :__enumBase()    - the value that is being traversed
      :__enumValue()   - the value of variable
      :__enumIsFirst() - is it the first enumerated item?
      :__enumIsLast()  - is it the last enumerated item?
   - defining new class or overloading existing one user can define
     his own behavior of FOR EACH iterating overloading chosen of above
     methods and/or the following ones:
      :__enumStart()
      :__enumSkip()
      :__enumStop()
     By default FOR EACH iterate all object instance variables

for example:
   a := "A"
   b := "B"
   FOR EACH a, b IN { 1, 2, 3, 4 }, "abcd"
      ? a, b   // prints: 1 a
               //         2 b
               //         3 c
               //         4 d
   NEXT
   ? a, b   // prints: A B

   // you can use EXIT statement inside the loop
   FOR EACH a IN { 1, 2, 3, 4 }
      IF a:__enumIndex() == 3
         ? a
         EXIT
      ENDIF
   NEXT

   arr := { 1, 2, 3 }
   str := "abc"
   FOR EACH a, b IN arr, str
      a *= 2
      str := Upper( str )
   NEXT
   // now `arr` stores { 2, 4, 6 }
   // however `str` still stores "abc"

Notice the difference:
   FOR EACH a IN someValue
      ? a:__enumIndex()      // prints current value of the index
      ? ( a ):__enumIndex()  // sends `__enumindex()` message to the current value
   NEXT


WITH OBJECT
-----------
Harbour supports the following statement:

   WITH OBJECT expression
      ...
   ENDWITH

   Inside this WITH OBJECT/END enclosure you can use the simplified
   form of sending messages to the object. You can use the syntax
   :message( [params] )
   :property
   to send messages to the object specified by `expression`

for example:
   WITH OBJECT myobj:a[ 1 ]:myitem
      :message( 1 )
      :value := 9
   ENDWITH

   The above code is equivalent to:
   myobj:a[ 1 ]:myitem:message( 1 )
   myobj:a[ 1 ]:myitem:value := 9

   Inside WITH OBJECT/END you can access (or even assign a new object)
   using a special reserved property :__withObject()

       The runtime error will be generated at the time of message
       sending (or property access/assign) if <objexpression>
       is not a value of type object.

for example:
   CREATE CLASS foo
      VAR name INIT "FOO"
   ENDCLASS

   CREATE CLASS bar
      VAR name INIT "BAR"
   ENDCLASS

   WITH OBJECT foo():new()
      ? :name                   // prints `FOO`
      ? :__withObject():name    // also prints `FOO`
      ? :__withObject := bar():new()
      ? :name                   // prints `BAR`
   ENDWITH