SIMPOL Documentation

SBL Commands and Functions and the SIMPOL Equivalents

The following table contains an alphabetical list of SBL key words and their SIMPOL equivalent together with some explanatory text describing the differences.

Table 20.2. Comparison of SBL commands and functions to SIMPOL equivalents
SBLSIMPOLComments
ASC().charval() The ASC() function in SBL returns the ASCII (OEM) value of the first character in the string that is passed as the argument. In SIMPOL the .charval() function returns the Unicode character value of the first character in the string passed as the argument.
BLANKtype(db1table).newrecord()

Creating a new record in a database in SIMPOL is done by calling the newrecord() of the associated database table object.

Unlike with SBL, the default formulae are not executed at the point in time of creating a new record, so it is the responsibility of the SIMPOL programmer to perform any default calculations and assign the results to the associated fields.

CALL!execute() The CALL command in SBL that is used to execute external programs has its equivalent in SIMPOL in the form of the !execute() system function. One current difference between the two is that the SIMPOL version does not create a shell, so if you are using it in Windows to call things like the COPY or DEL commands, you need to call the command shell with appropriate command line switches or call a batch file that contains the commands instead.
CHAR$().char() The CHAR$() function in SBL returns the value passed as an ASCII (OEM) character. In SIMPOL the .char() function returns a Unicode character that is the equivalent of the value passed as the argument.
DATE$()DATESTR()

The DATE$() function in SBL takes a date and an optional format string and returns the date as a string formatted using the format string passed. The SIMPOL version requires the format string to be passed. Supported formats are the same in both versions: "day month year", "month day year", or "year month day". Separators can be any character, though sensible choices should be made. The actual format string supports the following:

Table 20.3. 
ddDay no leading zero
0dDay with leading zero
zdDay with leading space
mmMonth no leading zero
0mMonth with leading zero
zmMonth with leading space
mmmThree letter abbreviated month name
mmmmMonth fully spelled out
yyTwo digit year
yyyyFour digit year


DAYSstring2date()

The SBL command DAYS takes either a date or a text containing a date and returns an integer representing the number of days since 01 January, 0001. The SIMPOL version only supports converting a date expressed as a string. It requires a format string in order to know how to process the date. It returns a date object represnting that time. The value of a date object is an integer containing the number of days since 01 January, 0001.

[Note]Note

Because of an error in the way SBL calculates the dates prior to the Gregorian Reform in England (September 2, 1752), the value of the days in SBL is 11 days off. Also, SIMPOL starts from 0, rather than 1, so the effect is actually a difference of 10 days. This normally makes no difference, but can become an issue if working with actual integer values and using the data in both SBL and SIMPOL as a hybrid system. Also, in SIMPOL no support is provided for the Gergorian Reform. Instead the Julian integer value for the number of days assumes no error occurred. For historical dates it would be necessary use your own date formatting function as this is considered a localization issue.

ENDno equivalent The SBL command END allows the program to stop executing. In SIMPOL programs will exit only when the reach an error condition or they exit through the end of the main() function.
ERR$(), ERRNO, ERROR, ON ERROR, RESUME, etc.No equivalent In SIMPOL there is no error handling in the form of interrupts such as is the case in SBL. Instead, most function calls that can cause an error take an error object and in some cases an error text object. In the case of an error, if the error object has been passed, then the error will be returned in the object. If no object has been passed, then the program will halt at that point with an error. Most syntax errors will be found during compilation and post-processing of the IDE. In some cases errors will occur at runtime but should normally be found during testing.
EXISTS()fileexists() In SBL the EXISTS() function has two variants. One variant checks whether the argument passed exists as a file in the file system. That functionality is provided for in SIMPOL by the fileexists() function. The other variant takes a value and an index and returns whether a record exists with that value in the target database table without changing the current record pointer in the target index. No exact equivalent exists for this since none is really needed. There is a function called lookup() that is found in the appframework.sml library and which takes an index object, a value, and an error variable and which returns a record object if a match is found, otherwise it returns .nul.
FCASE$().tcase() In SBL to convert a string such that only the first character is capitalized the programmer calls the FCASE$() function; the equivalent in SIMPOL is the .tcase() (titlecase) function.
FIX().fix() The FIX() function is commonly used in SBL to ensure that a floating point value is as close as possible to a desired number of decimal places as desired (floating point numbers are not precise because base ten fractions are not reliably representable in binary). In SIMPOL the more important use of the .fix() function is to truncate the exactly precise but potentially extremely large number of trailing digits from a value. It would not be uncommon to have a decimal value as the result of a division operation that had tens, hundreds, or even thousands of digits trailing the decimal point.
HRS()HRS() There is essentially no difference between these two functions, other than that in SIMPOL the parameter passed must be a time object. In both cases the number of hours in the time are returned as an integer.
IF().if() There is essentially no difference between these two functions, other than that in SIMPOL the argument must result in a Boolean value of either .true or .false, whereas in SBL zero is false and non-zero is considered to be true.
INSTR().instr() In both SBL. and SIMPOL these functions are used to determine whether some substring can be found in the target string. The only real difference between the two is that the SBL version can take an optional leading parameter that tells the function where in the string to begin looking. The equivalent in SIMPOL is to pass only the portion of the string in which to look, and then to adjust the value returned by adding the offset to the beginning of the substring that was passed.
IS()=@= In SBL the IS() fuction is used to compare if two variables refer to the same object. In SIMPOL this handled using an operator. This question can be negated in SBL by applying the NOT to the result of the function. In SIMPOL there are two equivalent operators for this: !@= and <@>.
LCASE$().lcase() In SBL to convert a string to lowercase the programmer calls the LCASE$() function and in SIMPOL the .lcase() function serves the same purpose.
LEFT$().lstr() These two functions are essentially identical in their function: they return the portion of the string from the first character until the end of the string or until the position passed whichever is less.
LEN().len() Both in SBL and SIMPOL these functions return the length of the argument passed. One difference is that in SIMPOL this is the length of the argument in characters that are Unicode characters, whereas in SBL these are single-byte ASCII (OEM) characters.
LIKE.like1() For the most part the two versions of LIKE work the same. There are a few more options in the SIMPOL version, such as optional case-sensitivity, but otherwise they should be compatible (other than the fact that the SBL version is an operator and the other is a function).
LOAD!loadmodulefile() The SBL LOAD command is used to load program files into memory and is most commonly used with the , NEW option to load a set of routines into memory for use by the program. It is also used to load queries, updates, text editor files, function key files, and labels definitions. Almost all of these latter items are better dealt with in SIMPOL as methods of the associated object. The function !loadmodulefile() is a SIMPOL system function for loading a compiled SIMPOL library so that its exported types and functions can be used. Although it is possible to directly include a library module in the resulting program when the program is compiled, it may be more efficient in some cases to load the module as needed, for example when the module may not always be needed.
LOCK() ppcstype1file.locked, ppcstype1record.locked, sbme1table.locktype, sbme1record.locktype In SBL the LOCK() serves to test whether a given record is locked in a database file. A similar capability exists in SIMPOL except that what is tested is the value of a property of the file (table) or record object. One difference in this is that this will only tell if the user has locked the record or table, it will not tell if others have done so (or even if another object in the same program has done so).
LOCK ALL ppcstype1file.lock(), sbme1file.lock() These two items are very similar, other than from an architectural perspective: with one being a command and the others being methods of types. In all cases the file is locked. In the case of the sbme1 type, it is also necessary to hold at least a shared lock on the table in order to create records.
MAX.max() The SIMPOL version of this function simply takes an unlimited number of arguments and returns the one that is of the highest value. The SBL version can only be used with arrays or on reports under special circumstances.
MID$().substr() These two functions are virtually identical, except that in SBL to return everything until the end of the string, the last parameter is left out, whereas in SIMPOL all three parameters are always required so to return everything the last parameter can be set to .inf.
MIN.min() The SIMPOL version of this function simply takes an unlimited number of arguments and returns the one that is of the lowest value. The SBL version can only be used with arrays or on reports under special circumstances.
MINS()MINS() There is essentially no difference between these two functions, other than that in SIMPOL the parameter passed must be a time object. In both cases the number of minutes in the time are returned as an integer.
MODmod These two operators do the same thing, they return the fractional portion of a division operation.
MOD()no equivalent The MOD() function in SBL is intended to indicate whether the current record in the file passed as the argument has been modified. Since there is no such thing as a current record (current file, etc.) in SIMPOL this function is meaningless. At some point when data-aware forms have been added there may be a method to indicate if any record on the form has been modified since it was read. That would be the appropriate location for such functionality.
NOTnot These two operators are essentially the same, other than that the SBL version operates with 0 and non-0 and the SIMPOL version works with .false and .true.
NOTHING.nul The literal value NOTHING in SBL is used exclusively together with the IS() to test whether an object variable refers to nothing. In SIMPOL this test can be carried out using the =@= operator and the literal value .nul. This value is used in many different areas and ways within SIMPOL.
QUITno equivalent The SBL command QUIT allows the program to suddenly exit, closing down the Superbase environment after calling the OnUnload event procedure of the Superbase object (if it was set). SIMPOL programs are self-sufficient so there is no additional environment to shut down and they will exit only when the reach an error condition or they exit through the end of the main() function assuming that all threads have also ended.
REM, '', ", // The REM statement and the single quote character can both be used to indicate a comment in an SBL program. The single quote character can also immediately follow a command in SBL. In SIMPOL both the single and double-quote characters can be used to indicate a comment but unlike SBL, in SIMPOL these are only considered to be comment characters if they are on the left side of an equation (at the beginning of a statement). Also, if another matching quote is found inside, then the comment is ended and must be followed by an end-of-line character or end of statement character (: or ;). Using this technique a comment can be embedded in the middle of a line of code. The only line-level comment is the double forward slash (//). This must be placed at the beginning of a statement (either at the beginning of a line or directly following an end of statement character and separated only by white space).
REPLICATE (svar$, nvar%%)nvar * svar The REPLICATE() is part of the standard BASIC repertoire and SBL includes this function to replicate a string a given number of times. This function is unnecessary in SIMPOL since it is possible to directly multiply a string by an integer and thereby replicate the string that many times.
RIGHT$().rstr() These two functions are essentially identical in their function: they return the portion of the string from the last character until the beginning of the string or until the number of characters backwards from the end of the string, whichever is less.
SECS()SECS() There is essentially no difference between these two functions, other than that in SIMPOL the parameter passed must be a time object. In both cases the number of seconds in the time are returned as an integer.
SELECT FIRST INDEX ""db1tablevar.select(lastrecord=.false, error=e)

One of the significant differences between SBL and SIMPOL is the fact that in SBL, the entire Superbase product is always present, and there is always a globally visible current database table (or file), for each database table (file) there is a current index, and each index has a current record that may be different for each index. There is also a currently loaded record. When working with multiple windows open, this gets even messier still, since each ViewWindow may have different database tables open, or even the same ones but with a different set of current indexes and records. This must be carefully managed using the SetSBLWindow() method of the Superbase object. In SIMPOL there are no global variables. To access a record from a database table a method of either the table, an index of the table, or even a record of the table is called. There is no current table, no current index, and no current record. Although the dataform1 type provides for a current master record for a data-aware form, this does interfere elsewhere in the system. A record object is the result of calling some form of select method. There can be as many record objects as the programmer wishes to create. They can be stored in lists or arrays. The logic behind how the select methods are designed is as follows:

  • table.select() — Tables know what is at the beginning and the end of the sequential order of the table.

  • index.select() — Indexes know what is at the beginning and the end of the index order.

  • index.selectkey() — Indexes know how to find a value in the index using a key.

  • record.select() — Records know where they are in whatever method selected them, and can get to the previous and next items in the same selection order, so if they were selected using an index, they can find the previous and next records in the same index, if selected using the sequential order of the table, they can find the previous and next items in the sequential order of the table.

The return value of a record selection in SIMPOL is a record object. If an error occurs, then the record object may be equal to .nul. Always pass an integer object to these methods to trap any error that occurs. The integer must be pre-initialized to 0, since the error variable will only be written to if an error occurs. If the variable is not set to 0, then the program may incorrectly assume that a pre-existing value was returned by the call to the method. Specific to this command, by using the double-quote "" argument for the INDEX parameter, Superbase is being told to select the first record in the sequential order of the table. Using the select() method of table object, SIMPOL is doing the same thing.

SELECT LAST INDEX ""db1tablevar.select(lastrecord=.true, error=e) See the prior entry for SELECT FIRST INDEX "" for details about how to select records using SIMPOL. In this particular case, by using the double-quote "" argument for the INDEX parameter, Superbase is being told to select the last record in the sequential order of the table. Using the select() method of the table object, SIMPOL is doing the same thing.
SELECT FIRST INDEX RecNo.TESTdb1indexvar.select(lastrecord=.false, error=e) See the prior entry for SELECT FIRST INDEX "" for details about how to select records using SIMPOL. Here, the RecNo index is being used as an argument to select the first entry in that index. In SIMPOL this can be done using a variable that refers to the RecNo index, or it may be done using valid object syntax to reach the index object. For example: db1tablevar!RecNo.index.select(lastrecord=.false) uses the table variable. From the db1tablevar variable the member operator (!) is used to retrieve the field object for the RecNo field, and then its index property is accessed using the dot (.) operator, and again using the dot (.) operator, the select() method is called.
SELECT LAST INDEX RecNo.TESTdb1indexvar.select(lastrecord=.true, error=e) See the prior entry for SELECT FIRST INDEX "" for details about how to select records using SIMPOL. See the prior entry for SELECT FIRST INDEX RecNo.TEST for details about how to select records using an index in SIMPOL. The only difference to the SELECT FIRST version is that the lastrecord parameter is assigned the value .true rather than the value .false.
SELECT KEY 123 INDEX RecNo.TESTdb1indexvar.selectkey(123, error=e, found=f) See the prior entry for SELECT FIRST INDEX "" for details about how to select records using SIMPOL. See the prior entry for SELECT FIRST INDEX RecNo.TEST for details about how to select records using an index in SIMPOL. In this particular case, the selectkey() method is being used. The value that is being looked up must match the data type of the field for which the index was created. The only variation of that is that an integer value can be used to search within indexes on date, time, and datetime fields. If the record is successfully found, then the boolean variable (which must be pre-initialized) that was passed to the found parameter is set to .true and the variable passed to the error parameter will be unchanged. If the found parameter is not passed, and the record is not found, then the return value will be .nul and an error value will be assigned to the variable that was passed to the error parameter.
SELECT NEXTdb1recvar.select(previousrecord=.false, error=e) See the prior entry for SELECT FIRST INDEX "" for details about how to select records using SIMPOL. As stated in that entry, the return value of a selection is a record object. To select the next record (or the previous one) the select() method of the record object is called, passing the appropriate value to the previousrecord parameter, in this case the value .false.
SELECT PREVIOUSdb1recvar.select(previousrecord=.true, error=e) See the prior entry for SELECT FIRST INDEX "" for details about how to select records using SIMPOL. As stated in that entry, the return value of a selection is a record object. To select the next record (or the previous one) the select() method of the record object is called, passing the appropriate value to the previousrecord parameter, in this case the value .true.
SET INDEX Name.TESTdb1recvar.selectcurrent(db1indexvar_Name, error=e) This command is supplied by Superbase to allow the programmer to change the controlling index of an already selected record. In SIMPOL, it is necessary to call the selectcurrent() method and to pass the desired index object to switch to a different controlling index. If no index parameter is passed, then the default is to use the value .nul, which results in the record being switched to having been selected using the sequential order of the table. It is important to remember this when reselecting a record with a lock, since otherwise the record may be switched away from the desired index without realizing it!
SELECT FIRST LOCK INDEX ""db1tablevar.select(lastrecord=.false, lock=.true, error=e) See the prior entry for SELECT FIRST INDEX "" for details about how to select records using SIMPOL. The only significant difference here is that in both cases the relevant locking parameter LOCK" or lock is being passed. In SBL if the locking operation fails, then an error occurs which may result in a call to a global error handler, or if the error has been disabled, then it will simply set the value of the ERRNO system value. In SIMPOL this will result in a return value of .nul, and the variable passed in the error parameter will be set to the error value that was the cause of the problem.
SELECT FIRST LOCK INDEX RecNo.TESTdb1indexvar.select(lastrecord=.false, lock=.true, error=e) See the prior entry for SELECT FIRST INDEX "" for details about how to select records using SIMPOL. See the prior entry for SELECT FIRST LOCK INDEX "" for details about how to select records with a lock using SIMPOL.
SELECT KEY 123 LOCK INDEX RecNo.TESTdb1indexvar.selectkey(123, lock=.true, error=e) See the prior entry for SELECT FIRST INDEX "" for details about how to select records using SIMPOL. In SBL it is a risky venture to use the LOCK together with a SELECT KEY statement, since if the selection fails to find the correct record, it will still find a record and will lock that one instead. It is better practice to make sure the record has been found and then use the SELECT CURRENT LOCK command to lock the record. The same is also true of SIMPOL, though it is possible to do this safely, simply by not passing a found parameter.
SELECT NEXT LOCKdb1recvar.select(previousrecord=.false, lock=.true, error=e) See the prior entry for SELECT FIRST INDEX "" for details about how to select records using SIMPOL. See the prior entry for SELECT FIRST LOCK INDEX "" for details about how to select records with a lock using SIMPOL.
SELECT CURRENT LOCKdb1recvar.selectcurrent(lock=.true, error=e) See the prior entry for SELECT FIRST INDEX "" for details about how to select records using SIMPOL. See the prior entry for SELECT FIRST LOCK INDEX "" for details about how to select records with a lock using SIMPOL. When selecting the current record in SIMPOL it is important to make sure that the index parameter is assigned an appropriate value since otherwise it will default to .nul and potentially change the current index (though only of the record that is returned). To retain the same index that was used in the original selection, it is easiest to just pass the index property of the record object, such as: db1recvar.selectcurrent(db1recvar.index, lock=.true, error=e).
SELECT REMOVEdb1recvar.delete(error=e) In SBL, once the record is deleted it is simply gone. In SIMPOL, the record object still exists and can be treated like a new record object that is not yet stored. This means that a record could be deleted and the record object could then be used (perhaps modified) to create a new record, and then that record could be saved.
SPACE$ (nvar%%)nvar * " " Probably related to its BASIC heritage, SBL includes this function to create a string a given number of space characters in length. This function is unnecessary in SIMPOL since it is possible to multiply a string by an integer and thereby replicate the string that many times.
STR$().tostr() or STR() The STR$() function in SBL allows a large number of different methods for formatting the number as a string. The equivalent function in SIMPOL simply formulates the number as a string and also requires the base to be provided. When used for base ten numbers, it is roughly equivalent to the command STR$(nvar%%, "."), except that in the case of a zero value the character 0 will be output whereas in SBL the empty string is the result. For a version that is directly compatible with the SBL version (except for the lack of support for scientific notation), look for the STR.sml library. It is also provided in source code. One difference between these is that the SIMPOL library function requires the user to provide an object that includes the numeric settings for decimal point, thousands separator, currency symbol, and whether the currency symbol is a prefix or suffix. This is necessary since there are no such global settings in SIMPOL.
THOUSECS()THOUSECS() There is essentially no difference between these two functions, other than that in SIMPOL the parameter passed must be a time object. In both cases the number of thousandths of a second in the time are returned as an integer.
TIME$()TIMESTR()

The TIME$() function in SBL takes a time value and an optional format string and returns the time as a string formatted using the format string passed. The SIMPOL version requires the format string to be passed. Supported formats are the same in both versions. Separators can be any character, though sensible choices should be made. The actual format string supports the following:

Table 20.4. 
hhHours
mmMinutes
ssSeconds
.sThousandths of a second
am12 hour clock


Some typical examples of time format strings for a time of 1:35 pm might be:

Table 20.5. 
hh:mm13:35
hh:mm:ss13:35:00
hh:mm am1:35 pm
hh:mm:ss.s13:35:00.000


TIMEVAL()string2time() In SBL the TIMEVAL() function takes either a time or a string representation of a time. The SIMPOL string2time() function only accepts a string and a format string and it returns a time object.
UCASE$().ucase() In SBL to convert a string to uppercase the programmer calls the UCASE$() function and in SIMPOL the .ucase() function serves the same purpose.
VAL().toval() The VAL() function in SBL is used to convert a string to a number. It is somewhat idiosyncratic in the way that it works. All leading whitespace is ignored, as are currency symbols and thousands separators and the number is returned that is found up until the first non digit character following the first decimal point or the end of the string is reached. The SIMPOL version of this in keeping with its support for multiple bases, takes the value, the characters to ignore, and the base to use for interpreting the string as a number. It might seem a bit awkward dealing with defining the characters to ignore in SIMPOL since it could be all of the Unicode character set, but in actuality it is quite easy, since it is also possible to subtract strings from strings in SIMPOL. To define the set of characters to ignore, simply subtract each of the characters that are desired from the string being evaluated, like this: n = .toval(s, s - "0" - "1" - "2" - "3" - "4" - "5" - "6" - "7" - "8" - "9" - ".", 10) , which will result in all of the desired characters being removed from the string and all of the remaining characters being ignored. For a more typical SBL version check the library for the VAL.sml.
WAIT FOR nvar%%!wait() These both wait for a specified amount of time. Only the duration and intervals are different.