Why different initialization logic ?

Started by Benjamin G., August 20, 2024, 12:17:58 PM

Previous topic - Next topic

Benjamin G.

Hello,

I wonder why an array static and dynamic don't react in the same way?

Sample code :

MAIN
  TYPE tdata RECORD
      i INTEGER
     ,s STRING
     ,f DECIMAL(10,2)
     ,d date
     END RECORD
  DEFINE fixarr array[1] OF tdata
  DEFINE dynarr DYNAMIC array OF tdata

  DISPLAY 'fixed array ....'
    DISPLAY '   fixarr[1].i :',IIF(fixarr[1].i IS NULL,' IS NULL',fixarr[1].i)
    DISPLAY '   fixarr[1].s :',IIF(fixarr[1].s IS NULL,' IS NULL',fixarr[1].s)
    DISPLAY '   fixarr[1].f :',IIF(fixarr[1].f IS NULL,' IS NULL',fixarr[1].f)
    DISPLAY '   fixarr[1].d :',IIF(fixarr[1].d IS NULL,' IS NULL',fixarr[1].d)
  DISPLAY 'dynamic array ....'
    DISPLAY '   dynarr[1].i :',IIF(dynarr[1].i IS NULL,' IS NULL',dynarr[1].i)
    DISPLAY '   dynarr[1].s :',IIF(dynarr[1].s IS NULL,' IS NULL',dynarr[1].s)
    DISPLAY '   dynarr[1].f :',IIF(dynarr[1].f IS NULL,' IS NULL',dynarr[1].f)
    DISPLAY '   dynarr[1].d :',IIF(dynarr[1].d IS NULL,' IS NULL',dynarr[1].d)
END MAIN
   
Results :
   
fixed array ....
   fixarr[1].i :          0
   fixarr[1].s : IS NULL
   fixarr[1].f : IS NULL
   fixarr[1].d :31.12.1899
dynamic array ....
   dynarr[1].i : IS NULL
   dynarr[1].s : IS NULL
   dynarr[1].f : IS NULL
   dynarr[1].d : IS NULL

Regards

Rene S.

* dynamic arrays are initially empty. New elements will be initialized to NULL
* static arrays are initialized to zero (Genero has inherited this from Informix). Initialized "to zero" means: the underlying memory is initialized with zeros.
* for some types (char, varchar, dec, money, text, datetime,  interval)  initializing "to zero" produces NULL values.
* some other (the numeric types: smallint, int, smallfloat, float) behave like their C counterparts: the variables have the value 0.
* DATE variables count days since 31.12.1899 - this implies initialize "to zero" produces 31.12.1899

BTW: Informix 4gl is not initializing local variables.

Benjamin G.

Hello,

documentation is very clear about that (https://4js.com/online_documentation/fjs-fgl-manual-html/#fgl-topics/c_fgl_variables_008.html)
the question was one of principle, should the programmer always assume that a variable is always initialized to NULL and is responsible for setting it to the correct value before using either with the "define initializer" or with a LET ...

regards

Sebastien F.

Benjamin,

You can rely on the fact that variables are initialized by default as described in the doc (=> depending on the data type, NULL or zero)

If the default value matches what you need, you don't have to initialize the variables with custom code.

Seb

Benjamin G.

that was our problem. Migrating an I4gl code to bdl

the initial I4gl code was :
  define i smallint
  define mytotals[100] of integer

let i = 0
foreach ...
    let i  i= i+1
    if i > 100 then
      message "ARRAY TO SMALL ..."
      exit foreach
    end if
    let mytotals=mytotals + someNotNullValueFromDb ...
  end foreach
 
  ---> code was ok

the new bdl code :
  define i smallint
  define mytotals dynamic array of integer

foreach ...
    let mytotals[i:=i+1]=mytotals + someNotNullValueFromDb ...
  end foreach

  code was ko : all mytotals  NULL ...

That was our initial problem ...

Sebastien F.

Your last code example does not seem to be the real one because mytotals is an array and it is used without an index.

Code (genero) Select
    let mytotals[i:=i+1]=mytotals + someNotNullValueFromDb ...

I am not sure to get the purpose of this code (do you sum sub-totals sequentially?)

Anyway, yes, when using a DYNAMIC ARRAY you need to initialize an INTEGER element to zero.

You may also take care of the value you add, if it's NULL it gives a NULL result.

Code (genero) Select
FOREACH ... INTO curr_value
    LET mytotals[i:=i+1] = 0
    LET mytotals[i] = <whatever> + NVL(curr_value,0)
END FOREACH



Seb

Reuben B.

Ben,

I think it is an interesting question you ask.  However remember that DYNAMIC ARRAY were added to the Genero language in the late 1990's / early 2000's so answer maybe lost in time.  We obviously have to respect Informix-4gl behaviour.

Also back in the day Informix-4gl could be compiled to p-code (.4go) and c-code (.4gi) and with c-code you had to explicitly initialise variables (or else you got the garbage that was in memory where your variable was allocated). So I think we sensibly followed the .4go behaviour.

I bump into this initialisation difference with simple examples ...

Code (genero) Select
MAIN
    DEFINE rec RECORD
        field1 INTEGER,
        field2 STRING,
        field3 DATE
END RECORD

    OPEN WINDOW w WITH FORM base.Application.getProgramName()
    INPUT BY NAME rec.* ATTRIBUTES(WITHOUT DEFAULTS=TRUE, UNBUFFERED)
END MAIN


will render with 0  in the INTEGER field and 31/12/1899 in the DATE field

Whilst with arrays

Code (genero) Select
MAIN
    DEFINE arr DYNAMIC ARRAY OF RECORD
        field1 INTEGER,
        field2 STRING,
        field3 DATE
END RECORD

    OPEN WINDOW w WITH FORM  base.Application.getProgramName()
    INPUT ARRAY arr FROM scr.* ATTRIBUTES(WITHOUT DEFAULTS=TRUE, UNBUFFERED)
END MAIN


the INTEGER and DATE field are blank

I have to remember to add INITIALIZE rec.* TO NULL in my simple INPUT examples so that I don't see the 0 and 31/12/1899.  The 0 and 31/12/1899 are annoying as a) they mean placeholder does not appear, and b) in the case of the dateedit, the calendar opens upto 31/12/1899 as opposed to TODAY if it is null.


I always thought the DYNAMIC ARRAY design decision and not initialising to 0's was something to do with runtime speed / memory consumption.  Run the following ...

Code (genero) Select
MAIN
DEFINE arr DYNAMIC ARRAY OF INTEGER
DEFINE i INTEGER
CONSTANT MAX_SIZE = 100000000


    LET arr[MAX_SIZE] = 0
    --FOR i = 1 TO MAX_SIZE
    --    LET arr[i] = 0
    --END FOR
    MENU ""
        ON ACTION ACCEPT
            EXIT MENU
    END MENU
END MAIN


... and note the memory consumption.

Now repeat with the comments removed which mimics what would happen if the dynamic array rows were populated with 0's.  Do you see higher numbers?


Reuben




Product Consultant (Asia Pacific)
Developer Relations Manager (Worldwide)
Author of https://4js.com/ask-reuben
Contributor to https://github.com/FourjsGenero

Benjamin G.

Hi,

I've made a test with Informix dynamic arrays (version 7.50FC4 compiled mode c4gl) and results are :

fixed array ....
   fixarr[1].i : -1
   fixarr[1].s : ÿèø
   fixarr[1].f : NULL
   fixarr[1].d : 31.12.1899
dynamic array ....
   dynarr[1].i : NULL
   dynarr[1].s : NULL
   dynarr[1].f : NULL
   dynarr[1].d : NULL

and with I4gl

fixed array ....
   fixarr[1].i : 0
   fixarr[1].s : NULL
   fixarr[1].f : NULL
   fixarr[1].d : NULL
dynamic array ....
   dynarr[1].i : NULL
   dynarr[1].s : NULL
   dynarr[1].f : NULL
   dynarr[1].d : NULL


As you can see, in C mode a static array contains garbage and the dynamic array is initialized to NULL
and in P-code (i4gl) a static array is initialized NULL and integer 0 and the dynamic array is initialized to NULL (seems like BDL ...)
The initial question was simply whether it wouldn't be more logical to always initialize an ARRAY to null in order to avoid confusion. I haven't found in the documentation any explanation of how an array is initialized by default.
For Seb, the example I've given is obviously not the production code, I just wanted to give the general idea of the situation.

Regards

Sebastien F.

Please provide the source code when you show such test output.

We will review the BDL doc and add notes about array element initializations.

Seb

Benjamin G.

Hi,

the BDL source code was in my first post
my last post source code was made for Informix 4gl  not BDL ...
Code (genero) Select

MAIN
  DEFINE s CHAR(40)
  DEFINE fixarr array[1] OF RECORD
      i INTEGER
     ,s CHAR(20)
     ,f DECIMAL(10,2)
     ,d date
        END RECORD
  DEFINE dynarr DYNAMIC array OF RECORD
      i INTEGER
     ,s CHAR(20)
     ,f DECIMAL(10,2)
     ,d date
        END RECORD

  DISPLAY 'fixed array ....'
    LET s =MYisNull(fixarr[1].i)
    DISPLAY '   fixarr[1].i : ',s CLIPPED
    LET s =MYisNull(fixarr[1].s)
    DISPLAY '   fixarr[1].s : ',s CLIPPED
    LET s =MYisNull(fixarr[1].f)
    DISPLAY '   fixarr[1].f : ',s CLIPPED
    LET s =MYisNull(fixarr[1].d)
    DISPLAY '   fixarr[1].d : ',s CLIPPED

  ALLOCATE ARRAY dynarr[1]
  DISPLAY 'dynamic array ....'
    LET s =MYisNull(dynarr[1].i)
    DISPLAY '   dynarr[1].i : ',s CLIPPED
    LET s =MYisNull(dynarr[1].s)
    DISPLAY '   dynarr[1].s : ',s CLIPPED
    LET s =MYisNull(dynarr[1].f)
    DISPLAY '   dynarr[1].f : ',s CLIPPED
    LET s =MYisNull(dynarr[1].d)
    DISPLAY '   dynarr[1].d : ',s CLIPPED
END MAIN

FUNCTION MYisNull(f)
  DEFINE f char(40)
  IF f IS NULL THEN
    RETURN "NULL"
  END IF
  RETURN f
END FUNCTION
[/color]


Regards