diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 3404cea6e6..919a788d2e 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -16,6 +16,18 @@ The license applies to all entries newer than 2009-04-28. */ + +2010-06-10 11:25 UTC+0200 Przemyslaw Czerpak (druzus/at/priv.onet.pl) + * harbour/src/rdd/dbf1.c + * minor formatting + + * harbour/doc/xhb-diff.txt + + added section about pre/post incrementation/decrementation and + = operators. + I think that you may find it interesting. I do not remember if I + documented it in the past and it's important feature which allows + Harbour programmers safely use pre/post ++/-- and = operations + for complex expressions with side effects. 2010-06-10 10:01 UTC+0200 Viktor Szakats (harbour.01 syenar.hu) * utils/hbmk2/hbmk2.prg + Added msvc version autodetection (works similarly diff --git a/harbour/doc/xhb-diff.txt b/harbour/doc/xhb-diff.txt index ebe5589575..a89b11f43f 100644 --- a/harbour/doc/xhb-diff.txt +++ b/harbour/doc/xhb-diff.txt @@ -852,6 +852,102 @@ command. +### PRE/POST INCREMENTATION/DECREMENTATION AND = OPERATORS ### +======================================================================== +Clipper compiling PRG code with expressions containing operators like +pre and post ++ and -- and also = internally translates them to +normal operators and then generated PCODE for such translated depressions, +i.e.: + a += 10 + b /= c + ++d + e-- + ? --f + ? g++ +is translated to: + a := a + 10 + b := b / c + d := d + 1 + e := e - 1 + ? ( f := f - 1 ) + ? g ; g := g + 1 + +As you can see it causes that modified expression is used more then once. +Usually twice but in some cases (i.e. '? g++' in example above even 3 times. +For simple expression like variables such internal compile time modification +is not visible for users and does not create any difference. +Anyhow if modified expression is complex one which is evaluated and changes +some states (expression with side effects) then such compiler behavior creates +very serious problems. In practice in Clipper it's not possible to use code +like: + aValue[ ++i ] += field->QUANTITY // (*) +because this line is translated to: + aValue[ ++i ] := aValue[ ++i ] + field->QUANTITY +then to: + aValue[ i := i + 1 ] := aValue[ i := i + 1 ] + field->QUANTITY +for := operator the left side is calculated first so effectively Clipper +generates code which works like: + aValue[ i + 2 ] := aValue[ i + 1 ] + field->QUANTITY + i := i + 2 +what is very far from the initial (*) expression. +In Harbour we decided to fix it and all expressions modified by pre and +post ++/-- and = operators are evaluated exactly once. It means that +now Harbour users can safely write code with (*) like expressions. +Anyhow if someone needs strict Clipper behavior then -kc Harbour compiler +switch restore it. +Here is simple code which illustrates it: + + proc main() + local a, i, n + a := afill( array( 10 ), 100 ) + i := n := 0 + while i < len( a ) + a[ ++i ] -= n++ + enddo + aeval( a, { |x| qout( x ) } ) + return + +This problem is also fixed in xBase++ so it's possible to exchange code +using such expressions between Harbour and xBase++. +In xHarbour the behavior of such expressions in in practice undefined. +In most of cases it behaves like Clipper (i.e. it gives the same wrong +results in above example) but not always because some not cleanly +implemented extensions changed above behavior for chosen operators +executed in some context (i.e. modifying -= to += in above example +causes that xHarbour generates correct code which give the same results +as Harbour and xBase++). Additionally so far no one has tried to control +such things in xHarbour compiler so the behavior of different operators +and/or context where they behaves differently has been changing few times +as side effect of some other modifications. + +The correct behavior of pre and post ++/-- and = operators is also +very important for OOP programmers because it guaranties that messages +are send to exactly the same object. This example illustrates it: + + proc main() + local o + o := errorNew() + ? "assign..." + ?? f( o ):cargo := 0 + ? "predec..." + ?? --f( o ):cargo + ? "postinc..." + ?? f( o ):cargo++ + return + func f( o ) + ?? " F()" + return o + +In Harbour and xBase++ function F() is executed only once for each +expression but in Clipper and xHarbour once for 'assign', then twice for +'predec' and finaly three times for 'postinc'. In this code function f() +returns the same object 'o' on each call so it's not a problem but code +where the expression can return different objects will not work correctly +so OOP programmers working with Clipper or xHarbour should remember about +it and not create such code. + + + ### GLOBAL / GLOBAL EXTERNAL (GLOBAL_EXTERN) ### ====================================================== xHarbour support application wide static variables called GLOBALs. diff --git a/harbour/src/rdd/dbf1.c b/harbour/src/rdd/dbf1.c index e4492c2d22..1b1d159996 100644 --- a/harbour/src/rdd/dbf1.c +++ b/harbour/src/rdd/dbf1.c @@ -1012,8 +1012,8 @@ void hb_dbfPutMemoBlock( DBFAREAP pArea, HB_USHORT uiIndex, HB_ULONG ulBlock ) * so I left it in DBF. */ HB_ERRCODE hb_dbfGetMemoData( DBFAREAP pArea, HB_USHORT uiIndex, - HB_ULONG * pulBlock, HB_ULONG * pulSize, - HB_ULONG * pulType ) + HB_ULONG * pulBlock, HB_ULONG * pulSize, + HB_ULONG * pulType ) { HB_TRACE(HB_TR_DEBUG, ("hb_dbfGetMemoData(%p, %hu, %p, %p, %p)", pArea, uiIndex, pulBlock, pulSize, pulType)); @@ -1082,7 +1082,8 @@ HB_ERRCODE hb_dbfGetMemoData( DBFAREAP pArea, HB_USHORT uiIndex, * so I left it in DBF. */ HB_ERRCODE hb_dbfSetMemoData( DBFAREAP pArea, HB_USHORT uiIndex, - HB_ULONG ulBlock, HB_ULONG ulSize, HB_ULONG ulType ) + HB_ULONG ulBlock, HB_ULONG ulSize, + HB_ULONG ulType ) { HB_TRACE(HB_TR_DEBUG, ("hb_dbfSetMemoData(%p, %hu, %lu, %lu, %lu)", pArea, uiIndex, ulBlock, ulSize, ulType)); @@ -1136,7 +1137,8 @@ HB_ERRCODE hb_dbfSetMemoData( DBFAREAP pArea, HB_USHORT uiIndex, * This function is common for different MEMO implementation * so I left it in DBF. */ -HB_BOOL hb_dbfLockIdxGetData( HB_BYTE bScheme, HB_FOFFSET *ulPos, HB_FOFFSET *ulPool ) +HB_BOOL hb_dbfLockIdxGetData( HB_BYTE bScheme, + HB_FOFFSET *ulPos, HB_FOFFSET *ulPool ) { switch( bScheme ) { @@ -1178,7 +1180,8 @@ HB_BOOL hb_dbfLockIdxGetData( HB_BYTE bScheme, HB_FOFFSET *ulPos, HB_FOFFSET *ul * This function is common for different MEMO implementation * so I left it in DBF. */ -HB_BOOL hb_dbfLockIdxFile( PHB_FILE pFile, HB_BYTE bScheme, HB_USHORT usMode, HB_FOFFSET *pPoolPos ) +HB_BOOL hb_dbfLockIdxFile( PHB_FILE pFile, HB_BYTE bScheme, HB_USHORT usMode, + HB_FOFFSET *pPoolPos ) { HB_FOFFSET ulPos, ulPool, ulSize = 1; HB_BOOL fRet = HB_FALSE; @@ -1238,8 +1241,8 @@ HB_BOOL hb_dbfLockIdxFile( PHB_FILE pFile, HB_BYTE bScheme, HB_USHORT usMode, HB * Get DBF locking parameters */ static HB_ERRCODE hb_dbfLockData( DBFAREAP pArea, - HB_FOFFSET * ulPos, HB_FOFFSET * ulFlSize, - HB_FOFFSET * ulRlSize, int * iDir ) + HB_FOFFSET * ulPos, HB_FOFFSET * ulFlSize, + HB_FOFFSET * ulRlSize, int * iDir ) { switch( pArea->bLockType ) {