Computers: Universe: Basic Types

Typelessness

All values in a UniVerse Basic program, whether they represent words, numbers, 'true/false' flags, or dates in the real world, are stored as strings of characters. This is what was meant by the assertion in the introduction to this course that UniVerse is 'typeless' (see The UniVerse Paradigm).

Whether a value is deemed to represent a piece of text, a number, a flag or a date depends entirely on the logic of your program and on the UniVerse Basic functions and operators you use. The following examples demonstrates a single value being treated first as if it represented a string, then a number, then a flag, and finally a date:

VALUE = 3479
* Concatenation assumes the value to represent a string
PRINT (VALUE : '2') ; * Prints 34792
* Addition assumes the value to represent a number
PRINT (VALUE + 2) ; * Prints 3481
* The IF statement assumes the value to represent a 'true' or 'false' flag
IF VALUE THEN PRINT 'TRUE' ELSE PRINT 'FALSE' ; * Prints TRUE
* This function assumes the value represents a date
PRINT (OCONV(VALUE, 'D')) ; * Prints 10 JUL 1977

Some operators and functions, like : (concatenation operator), obviously assume that your values represent strings. Others, like + (addition operator), obviously assume that they represent numbers. When using such operators it's not usually difficult to work out what UniVerse Basic will do. However, some are less obvious. Consider the following example. If the values are deemed to represent strings, they are clearly different. On the other hand, if they are deemed to represent numbers, they are the same. Which does UniVerse Basic do?

VALUE1 = 3479
VALUE2 = '03479'
IF VALUE1 = VALUE2 THEN PRINT 'SAME' ELSE PRINT 'DIFFERENT'

In fact, it prints SAME: thus demonstrating that, for the purposes of the comparison, the program assumed that both values represented numbers, and so concentrated on the value of the numbers they represented.

Stricty speaking, it would be more consistent for UniVerse Basic to support two operators, one doing a string comparison (say. =, and the other doing a numeric comparison (say, ==). After all, this is how it gets round the problem of addition: to add strings you use :, to add numbers +. However, this would seem odd, and UniVerse in general takes a very pragmatic view of such issues, preferring intuitiveness to mathematical consistency. It would also lead to errors. It would be annoying if your program reported a discrepancy between the total as printed on your invoice (say, 1000.00) and the sum of your net amount and your sales tax (say, 900+100 yielding 1000), just because you forgot to use == instead of =. It therefore decides for itself which you are likely to mean.

If you are ever in doubt about how an expression will be evaluated, you can test it without having to write, compile and run a test program. Use a RetrieVe enquiry like:

>LIST VOC SAMPLE 1 ID.SUP EVAL "IF 123='0123' THEN 'SAME' ELSE 'DIFFERENT'"

LIST VOC SAMPLE 1 ID.SUP EVAL "IF 123="0123" THEN "SAME" ELSE "DIFFERENT"" 12:08
:39  08-23-99  PAGE 1
IF 123='0123' THEN '
SAME' ELSE 'DIFFEREN
T'..................

SAME

Sample of 1 records listed.
>

This uses the EVAL keyword to test your expression: Handily, the expression itself appears as the column heading, and the value underneath it. (For information about EVAL, see Overriding Dictionaries).

Strings

If a value is deemed to represent a string, all its characters are significant. For instance:

VALUE1 = 'ABC'
VALUE2 = 'abc'
VALUE3 = ' ABC'
IF VALUE1 = VALUE2 THEN PRINT 'SAME' ELSE PRINT 'DIFFERENT' ; * Prints 'DIFFERENT'
IF VALUE1 = VALUE3 THEN PRINT 'SAME' ELSE PRINT 'DIFFERENT' ; * Prints 'DIFFERENT'
IF VALUE2 = VALUE3 THEN PRINT 'SAME' ELSE PRINT 'DIFFERENT' ; * Prints 'DIFFERENT'

Numbers

If a value represents a number, the form of the number is immaterial as long as UniVerse recognises it as being number. For instance:

VALUE1 = '12.3'
VALUE2 = '012.30'
VALUE3 = ' 1.23E1'
IF VALUE1 = VALUE2 THEN PRINT 'SAME' ELSE PRINT 'DIFFERENT' ; * Prints 'SAME'
IF VALUE1 = VALUE3 THEN PRINT 'SAME' ELSE PRINT 'DIFFERENT' ; * Prints 'SAME'
IF VALUE2 = VALUE3 THEN PRINT 'SAME' ELSE PRINT 'DIFFERENT' ; * Prints 'SAME'

Dates

A value can represent a date if it can also represent an integer, because it is then taken to be the number of days since the 31st of December 1967. For instance, the value 4, if deemed to represent a date, represents the 4th of January 1967. The date on which these notes were written (the 23rd of August, 1999) would be represented by the value 11558.

The rules for comparing dates are therefore the same as the rules for comparing numbers. If two values represent the same integer, they also represent the same date.

Clearly, it is no use printing the value 11558 on a screen or a report and expecting the user to understand it. A function called OCONV is therefore provided to 'convert for output'. The first parameter is the value to convert, and the second value the 'conversion specification'. The conversion specification for dates is D.

PRINT OCONV(11558, 'D') ; * Prints 23 AUG 1999

If you wish, you can be more specific in your 'conversion specification'.

PRINT OCONV(11558, 'D-DMY[2,2,2]') ; * Prints 23-08-99
PRINT OCONV(11558, 'D/MDY[2,2,4]') ; * Prints 08/23/1999
PRINT OCONV(11558, 'D DMY[2,A,4]') ; * Prints 23 AUGUST 1999

The conversion specification for dates runs as follows:
D for date
the character to separate the elements of the date (-, / and a space are used above)
the letters DMY arranged as you would like the day, month and year arranged
in square brackets, the number of digits in the date month and year: note the use of A for the alpha month.

The function ICONV() (convert from input) does the reverse:

PRINT ICONV('23 AUGUST 1999', 'D') ; * Prints 11558

Storing dates in this way makes date arithemetic extremely simple.

BASE.DATE = ICONV('23 AUG 1999', 'D')
WEEK.LATER = BASE.DATE + 7
PRINT OCONV(WEEK.LATER, 'D') ; * Prints 30 AUG 1999
WEEK.EARLIER = BASE.DATE - 7
PRINT OCONV(WEEK.EARLIER, 'D') ; * Prints 16 AUG 1999
DATE.OF.MILLENIUM = ICONV('01 JAN 2000', 'D')
PRINT DATE.OF.MILLENIUM - BASE.DATE : ' days till millenium' ; * Prints 131 days till millenium

Most applications store dates in fields in this way, using the third 'conversion' field of the corresponding dictionary record to ensure that a 'human readable' date is displayed in any column including the date. (See Data fields.)

True and false: 'boolean' flags

Any value can be deemed to represent truth or falsity. If it is numerically equal to zero or is an empty string, it represents false: if anything else, it represents truth.

IF '' THEN PRINT 'TRUE' ELSE PRINT 'FALSE' ; * Prints FALSE
IF ' ' THEN PRINT 'TRUE' ELSE PRINT 'FALSE' ; * Prints TRUE
IF 0 THEN PRINT 'TRUE' ELSE PRINT 'FALSE' ; * Prints FALSE
IF 1 THEN PRINT 'TRUE' ELSE PRINT 'FALSE' ; * Prints TRUE
IF 0.5 THEN PRINT 'TRUE' ELSE PRINT 'FALSE' ; * Prints TRUE
IF 0.0 THEN PRINT 'TRUE' ELSE PRINT 'FALSE' ; * Prints FALSE

The IF statements above may look a little odd, as you will more commonly see comparisons provided as conditions, such as:

IF 1 > 2 THEN PRINT '1 is bigger than 2' ELSE PRINT '1 is not bigger than 2'

But comparison operators like =, >, < work by evaluating to a '1' if the condition they represent is true, or a '0' if it is false. In the example above, the expression 1 > 2 is false, and so evaluates to 0, and therefore has the same effect as the statement IF 0 THEN... in the earlier example.