Way back in Feb. 2008, I started to write this article about an interesting @DATE pass-by-reference issue. Then I got sidetracked. So, this bug existed in whatever version was trialware at that time.
Guess what? It still exists in 10.3.7.0 on MS-Windows. So, here is how to time travel with @DATE.
Before we start, take this poll:
I had found a problem with the SUBR call in a I-Type field definition. After testing, it appears to be within a BASIC program as well and is to do with the pass-by-value and pass-by-reference differences. So I thought.
The routine is passed a date, which I use @DATE as the default for this month. For other months or days, I would add or subtract 30,60,90 etc.
Within the routine, the date variable is changed – adding 1 or 2 days based on some simple calculations. What I found was that the system date was changing as well!
So, I have below two routines to test the theory:
program RUN.TEST.DATE RESULT = 0 print "S@DATE = ", @DATE, oconv(@DATE, "D4") RESULT = subr("TEST.DATE", @DATE) print "E@DATE= ", @DATE, oconv(@DATE, "D4") end
subroutine TEST.DATE(RESULT, PARAM1 ) print "PDATE = ", PARAM1, oconv(PARAM1, "D4") print "@DATE= ", @date, oconv(@DATE, "D4") print "date() = ", date(), oconv(date(), "D4") PARAM1 += 1 print "ADDED A DAY" print "PDATE = ", PARAM1, oconv(PARAM1, "D4") print "@DATE = ", @DATE, oconv(@DATE, "D4") print "date() = ", DATE(), oconv(date(), "D4") RESULT = 0 return end
The output will be:
S@DATE = 15765, 28 FEB 2011 PDATE = 15765, 28 FEB 2011 @DATE = 15765, 28 FEB 2011 DATE() = 15765, 28 FEB 2011 ADDED A DAY PDATE = 15766, 01 MAR 2011 @DATE = 15766, 01 MAR 2011 DATE() = 15765, 28 FEB 2011 E@DATE = 15766, 01 MAR 2011
So, if you follow the PRINT statements, I start in the PROGRAM with 28 Feb, pass that through with @DATE as the parameter (pass by reference) and then added one day to it. The parameter within the subroutine changes to 1st March (PDATE) and also the date @DATE has also changed!
Since the parameter was passed by reference, the date (via @DATE) has also changed within the calling program (E@DATE).
If I change the passing of the parameter to pass-by-value by placing the parameter within brackets, the problem goes away.
If I change the passing parameter to DATE(), then the problem does not occur. So, what is the difference between @DATE and DATE()?
Well, I did discover something which I was not aware of: @DATE is the “internal date when the program was invoked”. This is from the UniBasic Reference documentation. I had always assumed that it was the system date now. Appears not! You learn something new everyday…
And DATE() “… return(s) the numeric value of the internal system date.” That makes sense. OK…
So, @DATE (and assuming that all derived @ values e.g. @DAY) are actually system variables that are created at the time of the program is invoked (run). And they are mutable. That is, they can be changed.
And this is all correct!
Oh, Yes. In the Appendix E of the UniVerse Basic Manual, there is a list of the @variables and “…denoted by an asterisk (*) are read-only. All others can be changed by the user.”
@DATE, @DAY, @MONTH and a whole bunch of others are mutable.
So, if you want to fudge your time sheets within your departments time-sheet software, in the next maintenance cycle, refactor to use @DATE and @TIME. Only joking, of cause.
So, recapping; DATE() is the CURRENT system date; @DATE WAS the date that the program was started, and if you started it late, you can change it. And all the subroutine parameter passing? Not really relevant; it was how I re-found the knowledge of @DATE.
Now, who can be honest here? How many readers thought that @DATE and DATE() were interchangeable?