Ask Reuben
Initializer Rules
Why does sometimes a date variable contain NULL and other times it contains 31st December 1899?
Why does sometimes an integer variable contain NULL and other times it contains 0?
In my role I am frequently creating small examples and it used to annoy me that sometimes a date example would have a DATEEDIT widget with a value that defaulted to 31/12/1899 and sometimes it wouldn’t. I had got into the habit of setting the date to TODAY so that when I opened the calendar widget I did not have to scroll through many years to enter a relevant date. A recent forum post (thank you Benjamin G) sent me off down a rabbit hole that helped to explain why the date variable had the value it did and why sometimes it did not have that value.
The relevant documentation pages were this one on Variable default values and this section on Default values when adding new elements in Dynamic Arrays.
Essentially Informix-4gl had the behaviour that the underlying memory for variables were filled with 0’s. As a result, numeric types such as INTEGER, SMALLINT but not DECIMAL would have an initial value of 0, and DATE would have an initial value of 31/12/1899 (number of days since 1/1/1900 -1).
When we added DYNAMIC ARRAY in one of the first iteration of Genero, as the memory for Dynamic Arrays was allocated on demand, this filling of memory variables with 0 did not occur and hence the initial values for these same data types would be NULL.
You can see this with the following example …
MAIN TYPE recType RECORD s STRING, i INTEGER, d DATE END RECORD DEFINE rec recType DEFINE s_arr ARRAY[10] OF recType DEFINE d_arr DYNAMIC ARRAY OF recType DISPLAY "*** Record ***" DISPLAY "String=",rec.s DISPLAY "Integer=", rec.i DISPLAY "Date=", rec.d DISPLAY "*** Static Array ***" DISPLAY "String=", s_arr[1].s DISPLAY "Integer=",s_arr[1].i DISPLAY "Date=", s_arr[1].d DISPLAY "*** Dynamic Array ***" DISPLAY "String=", d_arr[1].s DISPLAY "Integer=", d_arr[1].i DISPLAY "Date=", d_arr[1].d END MAIN
… which produces the following output …
*** Record *** String= Integer= 0 Date=31/12/1899 *** Static Array *** String= Integer= 0 Date=31/12/1899 *** Dynamic Array *** String= Integer= Date=
Note how for Record and Static Array, the Integer and Date elements have a value whilst for a Dynamic Array the value is blank (null).
These decisions were made in the early 2000’s or earlier. For some understanding to the DYNAMIC ARRAY behaviour, ask yourself what would you expect intermediate rows to be populated with if I had added row 100 instead of row 1. Rows 1 to 99 would need to have its memory set to 0 but these rows have not had their memory allocated yet. Also consider the case of a temporary row in an INPUT ARRAY, is a row touched if the user accepts the default value of 0?
The question might then be what can you do to avoid this inconsistency. There is no fglprofile flag to favour one behaviour over the other.
What you can do to avoid 0 and 31/12/1899 is to use the =NULL variable initializer. Modify the above definitions to be
DEFINE rec recType = NULL DEFINE s_arr ARRAY[10] OF recType= NULL
and you will see the values are now NULL instead of 0 and 31/12/1899 for the integer and date element. You could use
INITIALIZE rec.* TO NULL
but for an array you would have to have a FOR loop for every row, hence I lean towards the newer = NULL initializer syntax.
To go the other way for a dynamic array and set the same initial values as a record and static array you would have to populate the new row with an empty record when you create the new dynamic array element …
LET d_arr[1].* = rec.*
… you would also have to do that for any intermediate rows that have not been similar initialized so I would be very surprised if anyone went down this road.
As part of that forum discussion, we did review the documentation page . It might not be immediately obvious that you can use =NULL as an initializer for a record or array but you can.