FutureBasic Logo

<<    Index    >> FutureBasic 5

Appendix C - Data Types and Data Representation   appendix



I. Integers
Integers can be represented as literals, as symbolic constants, or as variables.

I.1 Integer Literals
Note: Hexadecimal, octal, binary and quoted literals reflect the actual bit patterns of the integers as they're stored in memory. These may be interpreted either as positive or negative quantities, depending on which types of variables they're assigned to. If they're not assigned to any variable, they're generally interpreted as positive quantities.

I.2 Symbolic Constants
A symbolic constant is an identifier preceded by an underscore character. There are many symbolic constants which have pre-defined values in FutureBasic. You can also define your own symbolic constants within your program, either by using a begin enum...end enum block; or a dim record...end record block; or by using a "constant declaration" statement. A constant declaration statement has this syntax:
_constantName = staticExpression
where _constantName is a symbolic constant which has not been previously defined, and staticExpression is a "static integer expression" (see Appendix D - Numeric Expressions). The value of staticExpression must be within the range -2,147,483,648 through +2,147,483,647. Once a symbolic constant has a value assigned to it, that value cannot be changed within your program. Like all constants, a symbolic constant has a global scope.
A constant declaration may also include pascal style strings using one of the following formats
_constantName$ = "I am a string constant"
_constantTab$ = 9 : rem chr$(9) = tab character
_constantCR$ = 13 : rem chr$(13) = carriage return
_twoByteKanjiChar = 10231: rem KCHR$(10231)

I.3 Integer Variables
There are six different types of integer variables in FutureBasic; they differ in the amount of storage space they occupy, and in the range of values they can represent. An integer variable's name may end with a type-identifier suffix which indicates its type; alternatively, you can declare an integer variable's type by using the as clause in a dim statement. If a variable has no type-identifier suffix, and wasn't declared with an as clause, then FutureBasic checks whether there are any def<type> statements which are applicable to the variable. Finally, if the variable can't be typed by any of the above means, FutureBasic assigns the type "signed short integer" to the variable. Arrays of integers, and integer record fields, are typed by similar means.

TypeStorageRangeType identification
signed byte1 byte-128..+127x'
Dim x As Byte
Dim x As Char
unsigned byte1 byte0..255x``
Dim x As Unsigned Byte
Dim x As Unsigned Char
signed short integer2 bytes-32768..+32767x%
Dim x As Int
Dim x As Word
Dim x As Short
unsigned short integer2 bytes0..65535x%`
Dim x As Unsigned Int
Dim x As Unsigned Word
Dim x As Unsigned Short
long integer4 bytes-2147483648..+2147483647x&
Dim x As Long
Unsigned long integer4 bytes0..4294967295x&`
Dim x As Unsigned Long

II. Real Numbers
"Real numbers" are numbers which may have a fractional part. They can be represented as literals or as variables.

II.1 Real Number literals
mantissa is a string of decimal digits with an optional decimal point, optionally preceded by "+" or "-"; exponent is a string of decimal digits, optionally preceded by "+" or "-".
Examples: 3e-20 -6.7E4 0.05E+14
The value of a number expressed in scientific notation is:
mantissa 10exponent

II.2 Real Number variables
There are three types of real number variables in FutureBasic; they differ in the amount of storage space they occupy, the range of values they can represent, and their precision (number of significant digits).

II.2.1 Fixed-point Reals
A fixed-point real number variable must be declared in a dim statement, using the as Fixed clause. It's accurate to about 5 places past the decimal point, and can handle numbers in the range of approximately -32767.99998 through +32767.99998. A fixed-point variable occupies 4 bytes of storage.

II.2.2 Floating-point Reals
FutureBasic supports two kinds of floating-point real number variables. A floating-point variable's name may end with a type-identifier suffix which indicates its type; alternatively, you can declare a floating-point variable's type by using the as clause in a dim statement. If a variable has no type-identifier suffix, and wasn't declared with an as clause, FutureBasic checks whether there are any defsng <letterRange>or defdbl <letterRange> statements which are applicable to the variable. Floating-point arrays, and floating-point record fields, are typed by similar means.
The methods used by FutureBasic when handling one of these variables can be modified by you. A set of constants is maintained in a file in the headers folder. (Path: FutureBasic Extensions/Compiler/Headers/UserFloatPrefs). If you want to change these parameters for all of your projects, copy the file named "UserFloatPrefs" into the User Libraries folder. The User Libraries folder is located at the same level as the editor.
//
// Required Floating Point Constants //
//
_NumberLeadingSpace = _True //FBII Default = _true
_RoundUpFloat2Long = _true // Un-remark to round up Float to Integer

Generally speaking, double-precision floating-point variables occupy more storage, represent a greater range of values, and have greater precision than single-precision floating-point variables. However, the exact storage space, ranges and precisions of these types depend on the target CPU of the compiled program (Note: the storage space for variables can vary between CPU devices. When in doubt, use the sizeof function to make a definite determination of the size of the variable.)
Type
Type Identification
single-precision
x! (4 bytes)
dim x as single
double-precision
x# (8 bytes)
dim x as double

III. Strings
Note:The term 'Strings' in the following sections refers to pascal strings and not CF/NS strings.

A string is a list of up to 255 characters, which is usually interpreted as text. Strings can be represented as literals or as variables.

III.1 String Literals
A string literal is a group of characters surrounded by a pair of double-quotation marks (note: in certain contexts, such as in data statements, the quotation marks may be optional). If the string literal contains a pair of contiguous double-quotes, they are interpreted as a (single) embedded double-quote mark and treated as part of the string, rather than as a delimiter. Example:
print "I said, ""Hello."""
program output:
I said, "Hello."

III.2 String Variables
You can specify a string variable by appending the type-identifier suffix "$" to the variable's name; alternatively, you can declare a variable as a string by using the as Str255 clause in a dim statement. If a variable has no type-identifier suffix, and wasn't declared with an as clause, then FutureBasic checks whether there are any defstr <letterRange> statements which are applicable to the variable. String arrays, and string record fields, are typed by similar means.
A string variable declared as Str255 can hold up to 255 characters. The maximum number of characters that other string variables can represent is determined by the maxLen value specified in a dim statement, or by the value specified in the DEFLEN statement. If neither of these values was specified, then the string variable can hold a string of up to 255 characters.
Internally, strings are stored in "Pascal format." Pascal format begins with a "length byte" which is interpreted as a number in the range 0 through 255. The length byte's value indicates the number of characters currently in the string. The length byte is followed immediately by the string's characters, one byte per character. FutreBasic3 always allocates an even number of bytes for a string variable in memory; this is enough to include the length byte, plus enough character bytes for the variable's maximum string length, plus an exta "pad" byte (if necessary) to make the total come out even. Use the sizeof function to determine the number of bytes allocated to a particular string variable.

IV. Containers
Containers are FB runtime managed pointers that hold up to 2 gigabytes( more if app is 64-bit ) of ASCII data. Containers may be identified by a double dollar sign (dim myContainer$$) or in a dim as statement (dim as CONTAINER myContainer).
Containers are always global and dimensioning one inside of a local function will result in an error message during compilation. When a container is first dimensioned, it is a pointer variable with a value of zero. Once data is placed in the container, a pointer is allocated and the data is moved to it. To dispose of the allocated pointer, set the container to a null string with myContainer$$ = "".

Because a container may hold ASCII or numeric information, there are some trade-offs. The first is speed. Numeric values stored in containers are first converted to ASCII. When math operations are required, the data is reconverted before the calculation is performed. Best recommendation: don't do math inside containers.

Another limitation relates to how containers are filled. Since FutureBasic has no idea what data may be in the container, it has to evaluate the information on the other side of the equal sign to see what it should be doing. If this data is a series of Pascal strings, then the container must be limited to 255 characters.
myContainer$$ = a$ + b$ + c$
If the information is to be a concatenated string and the right side of the equal sign contains only Pascal style strings, you must approach things from a different direction.
myContainer$$ = a$
myContainer$$+= b$
myContainer$$+= c$

In some cases, the compiler will not be able to determine what type of operation you had in mind. For instance...
a$$ = b$$ + c$$
The compiler has no clue as to whether it should concatenate strings or add numbers. You can force the correct operation by inserting an additional operator.
a$$ = b$$ + c$$ + 0 : rem math
a$$ = b$$ + c$$ + "" : rem strings

This is not a problem with other math operators like the minus sign or the multiplication (asterisk) symbol as these cannot pertain to strings.

Containers may not be compared in the traditional sense. This is because a comparison by its very nature must return a numeric value. If you execute a statement like print a$ = b$ the result will be zero (_false) or -1 (_zTrue).
A substitute function can handle the comparison for you.
rslt& = fn FBcompareContainers(a$$,b$$)
If a$$ is less than b$$ then the result will be negative and will represent the character position at which the difference was found. If rslt& is -3000 then a$$ and b$$ were identical for the first 2999 characters, at which time the next character in b$$ was found to be less than the one in a$$.
When rslt& is zero, the containers are equal.
When rslt& is positive, it points to the character position at which it was determined that a$$ is greater than b$$.

You can extract the pointer to the container as follows:
p = fn ContainerToPointer( @myContainer ) which replaces the previous handle-based version ( i.e. hndl& = [@myContainer$$] )
Be aware that the pointer may be zero if the container has been cleared or if it was never initialized.

To put information into a container from a pointer use:
fn ContainerFromPointer( @myContainer, p, size ) this replaces the previous handle-based version ( i.e. a$$ = &hndl& )

The percent sign (%) syntax to fill a container with a TEXT resource ID is obsolete and not supported

Complex expressions that include containers and/or Pascal strings on the right side of the equal sign will fail. Instead of using:
c$$ = c$$ + left$$(a$$,10)
d$$ = c$$ + a$
Use:
c$$ += left$$(a$$,10)
d$$ = c$$
d$$ += a$


Another example. Instead of using:
c$$ = right$$( a$$, 8 ) + left$$( b$$, 3 )
Use:
c$$ = right$$( a$$, 8 )
c$$ += left$$( b$$, 3 )

The FB header, Util_Containers.incl, and the FB Examples' 'Containers' folder are good sources of more information.
Note: Containers work fine for ASCII data but CF/NS strings should be considered for Unicode data.

V. Pointers
A pointer variable is always declared in a dim statement. It can be declared using the as pointer (or as PTR) clause, or an as ptrType clause, where ptrType is a type which was previously identified as a pointer type (in a #define statement). If the as pointer clause included a to clause, then the variable is identified as "pointing to" a data structure of the indicated type; otherwise it's considered a "generic" pointer.
The value of a pointer is actually a long integer; it's the address of a data structure. In some cases a pointer's value may be _nil (zero), which indicates that the pointer currently isn't "pointing to" anything.
If you declare a pointer variable as pointing to a particular record type, you can use the pointer variable to refer to specific fields within a record (see Appendix B - Variables, for more information).

VI. Handles
A handle variable is always declared in a dim statement. It can be declared using the as Handle (or as HNDL) clause, or an as hdlType clause, where hdlType is a type which was previously identified as a Handle type (in a #define statement). If the as Handle clause included a to clause, then the variable is identified as a handle to a data structure of the indicated type; there are also a couple of pre-defined types (RgnHandle and TEHANDLE) which are recognized as handles to particular types of MacOS structures (specifically: to regions and TextEdit records). If the variable is declared simply "as Handle" (with no to clause), it's considered a "generic" handle.
The value of a handle is actually a long integer; it's the address of a "master pointer" which points to a relocatable block that contains a data structure. In some cases a handle's value may be _nil (zero), which indicates that it doesn't currently refer to any data structure.
If you declare a handle variable as referring to a particular record type, you can use the handle variable to refer to specific fields within a record (see Appendix B - Variables, for more information).

VII. Records
A record is a (usually small) collection of data items that are stored together in memory. You can access an entire record as a unit, or access its data elements individually. Unlike an array, whose elements are all of the same type, the elements of a record (also called its "fields") can be of differing types. A record variable must be declared in a dim statement, using the following syntax:
dim recordName as recordType
where recordType is previously-defined record type. You can define a record type and its fields by using a begin record...end record block. In addition, FutureBasic recognizes two built-in record types: Rect and Point. You use the recordName.field syntax to access the fields of a record variable (see Appendix B - Variables).

Compatibility of Types
You can assign values of one type to variables of another type, sometimes with certain restrictions. The following table shows which kinds of values can be assigned to which kinds of variables.

Values


Variables
Sign.
Byte
Uns.
Byte
Sign.
Byte
Uns.
Byte
Sign.
Byte
Uns.
Byte
FixedSimpleDoubleStringPointerHandleRecord
Sign. ByteOK222222,32,32,32,3,8NONONO
Uns. Byte1OK1,221,221,2,31,2,31,2,31,2,3,8NONONO
Sign. WordOKOKOK22232,32,32,3,8NONONO
Uns. Word1OK1NO1,221,31,2,31,2,31,2,3,8NONONO
Sign. LongOKOKOKOKOK232,32,32,3,81010NO
Uns. Long1OK1OK1,2OK1,31,2,31,2,31,2,3,81010NO
FixedOKOKOK222OK2,42,42,4,8NONONO
SimpleOKOKOKOK444OK44,8NONONO
DoubleOKOKOKOKOKOKOKOKOK8NONONO
String5,85,85,85,85,85,85,85,85,855,85,8NO
PointerOKOKOKOKOKOK2,32,32,32,3,86NONO
HandleOKOKOKOKOKOK2,32,32,32,3,8OK7NO
RecordNONONONONONONONONONONONO9

Notes:
1. Assigning a negative value to an unsigned integer type may produce unexpected results.
2. Assigning a number outside of a type's range may produce unexpected results.
3. Result will be rounded to the nearest integer.
4. Some digits of precision may be lost.
5. Make sure that the destination string variable is declared with sufficient storage.
6. Both must be pointers to the same type (or both "generic" pointers).
7. Both must be handles to the same type (or both "generic" handles).
8. Automatic string/number translation requires a special preference setting; otherwise, use the val[&] or str$ functions.
9. Both must be the same record type.
10. Information about the type of thing referenced (by the handle or pointer) is lost when the handle or pointer value is assigned to a long integer variable. (This can sometimes be useful, if you want to "coerce" a pointer to point to a different type.)