Copyright © 2001, SNAP Innovation Softwareentwicklungsgesellschaft mbH. All rights reserved.The information contained in this document applies to:
Last major update to this document on November 16th, 1999.
- PrimeBase Database Server 4.0, build #4009 and higher
- PrimeBase Virtual Machine 4.0, build #4009 and higher
Java and JavaScript are trademarks of Sun Microsystems, Inc.
All other product names mentioned herein are the trademarks of their respective owners.
1. Introduction2. The PrimeBase Virtual Machine
"Hosting" the PBVM3. Concepts
PBT as Middleware
PBT and DAL
Virtual Machine SessionsGetting Started4. Variables
Submitting Requests
Compilation
Retrieving Output
Subprograms
Statements
Comments
Primitive Data Types
Arrays, Classes and Objects
Identifiers
Variables and Constants
Scope and Namespace
Operators
Flow Control
Procedures
Error handlingConstants5. Primitive TypesBOOLEAN type6. Reference Types
Integral types
Floating point types
Fixed point types
Date and Time Types
Textual types
BINARY typesTests on References7. Special TypesGeneric8. Operators
Null
ObjnameBOOLEAN Operators9. Procedures and Functions
Comparison Operators
Arithmetic Operators
Bit-wise Operators
Data Type Conversion Operators
Unary Operators
Assignment Operators
Cursor-based Reference OperatorDeclaring a Procedure10. Flow Control
A minimal Procedure Declaration
The maximal Declaration
Global Procedures
Function Procedures - with single result
Procedures with multiple results
Procedures with arguments and defaults
Scope
Static Statement BlocksIF11. Error Handling
SWITCH, CASE, DEFAULT
LABEL, GOTO
BREAK
CONTINUE
WHILE
DO WHILE
FOR
FOR EACH12. Classes
Forward Declarations13. Objects
Class Access
Inheritance
Final Classes
Abstract Classes
Class Redeclaration
Class Members
Access Operators
Static Members
Member AccessConstructor14. Arrays
Member Variable Initialization
Final Member Variables
finalize() as Destructor
clone()
getClass()
Member Procedures and Functions
Static methods
Abstract methods
Overloading
Overriding
Final Methods
Method Access
ReflectionArray Methods15. Cursors
Numerically Indexed Array
Associative ArrayExplicit call17. ConceptsThe Data Access Language18. Basic Elements
Sessions - the DAL "runtime" Concept
System ArchitectureData Type Conversions19. Control Statements
Basic Elements
Functions Calls: f()
Cursor Based Reference: ->DBMS Statements20. Basic StatementsDESCRIBE DBMSDatabase Statements
DESCRIBE OPEN DBMS
OPEN DBMS
CLOSE DBMS
USE DBMSDESCRIBE DATABASES
DESCRIBE OPEN DATABASES
OPEN DATABASE
CLOSE DATABASE
USE DATABASE
DESCRIBE TABLES
DESCRIBE COLUMNSVariable Manipulation21. Program ConstructsDECLAREExecute Statements
UNDECLARE
SETEXECUTE FROMPrint Statements
EXECUTE IMMEDIATE
EXECUTE FILE
PRINTALL
PRINTCTL
PRINTF
PRINTINFO
PRINTROWERROR
ERRORCTLConditional/Branch Statements22. PBCTL - Configuring PrimeBase DAL CompatibilityIFIteration Statements
SWITCH
LABEL
GOTO
BREAK
CONTINUEWHILEProcedure Statements
DO
FOR
FOR EACHDECLARE PROCEDURE
RETURN
CALL23. Encrypting PrimeBaseTalk files
Appendices
A. System VariablesA.1 Format Control VariablesB. Built-in Functions$ampm, $datefmt, $day, $decfmt, $moneyfmt, $month, $timefmt, $tsfmtA.2 Constants$false, $null, $trueA.3 System Control VariablesData Type Constants:
$BOOLEAN, $CHAR, $date , $DECIMAL, $FLOAT, $integer, $LONGBIN, $LONGCHAR, $MONEY, $smfloat, $SMINT, $time, $timestamp, $VARBIN, $VARCHAR$sqlnotfound, $version$sqlcode, $sqlcode2, $switchA.4 Cursor Control Variables$aborttime, $colcnt, $cursor, $locktimeout, $maxrows, $rowcnt, $rowlocking, $rowsaffected, $rowsperpageA.5 DBMS Lookup Variables$dbmszone, $dbmsbrand, $dbmsprotocolA.6 Login Information$logintime, $connid, $userB.1 String FunctionsC. Golfers Database$format(), $hash(), $left(), $locate(), $ltrim(), $right(), $rtrim(), $substr(), $tolower(), $toupper(), $trim()B.2 Variable Information Functions$exists(), $len(), $scale(), $typeof()B.3 Cursor Information Functions$cols(), $collen(), $colname(), $colplaces(), $coltype(), $colwidth(), $currentrow(), $rows()B.4 Cursor Manipulation Functions$deleterow(), $insertrow(), $updaterow()B.5 File I/0 Functions$close(), $create(), $delete(), $fileexists(), $filestamp(), $getcwd(), $geteof(), $gettempdir(), $listdir(), $map(), $mkdir(), $nativepath(), $open(), $openreadonly(), $read(), $readline(), $rename(), $rmdir(), $seteof(), $write(), $writeline()B.6 Miscellaneous Functions$base64encode(), $encrypt(), $errorstring(), $getenv(), $md5(), $now(), $ostype(), $putenv(), $sendmail(), $sendmailxt(), $yield()
PrimeBaseTalk (PBT) is an object oriented language specifically designed for the programming of "server-side" functionality common to intra- and internet Web sites.The language includes the best ideas and concepts from 4 generations of languages, and combines them seamlessly and systematically. This includes:
The combination of such tools applied to any problem is extremely effective and allows for rapid application development.
- Structured programming constructs, such as IF, WHILE, DO, etc. from 3rd generation languages such as C and Pascal.
- Integrated database access and cursors made popular by 4th generation languages such as COBOL. In particular, the language incorporates the relational database standard: SQL or Structure Query Language.
- High level features such as automatic garbage collection and a built-in compiler found in "experimental" languages such as Lisp and Prolog.
- The object-oriented paradigm from languages like C++ and Java™.
PrimeBaseTalk is also DAL (Data Access Language) compatible and, as a result, supports code previously written to access the PrimeBase Database Server. In addition, it is "Java-like", making it easy for experienced Java programmers to use. This, and other factors have determined the design of PrimeBaseTalk, as will be discussed below.
Many of the examples in reference manual make use of a sample database, called the Golfers database. The tables and columns of the Golfers database are explained in detail in Appendix C.So if you want to try any of these examples yourself you may want to copy and paste the Create Script into a file execute them in the PrimeBase Automation Client (PBAC) or the PrimeBase SQL Database Server console using the EXECUTE FILE command:
Also make sure you open the Golfers database in PBAC or the server console prior to trying any of the examples contained in this reference manual. You do this by issuing the following:EXECUTE FILE "golfersdb.sql" LOCATION "c:\"; <press ENTER> go <press ENTER>OPEN DATABASE Golfers; <press ENTER> go <press ENTER>
The PrimeBase Virtual Machine (PBVM), is responsible for compiling and executing programs written in PBT. To do this the PBVM allows the creation of multiple independent "runtime environments", also known as sessions. Each session has its own global variables and execution thread, and runs independently of other sessions.The PBVM supports various API's (Application Programming Interfaces) common to database applications, including DAL/DAM (the original Data Access Language and Data Access Manager API's from Apple™), ODBC (Open Database Connectivity from Microsoft™), JDBC (Java Database Connectivity from Sun™ Microsystems) and EOF Adaptor (Enterprise Objects Frameworks Adaptor from Apple).
The application uses one of these API's to create and destroy a session, submit and run a PBT program and receive output from the running program. Programs are submitted as a combination of text and BINARY data. The built-in compiler transforms the program into an internal "byte-code" form which can be executed by the Virtual Machine. A program running in a session may exit (normally or due to an error). After this point the execution thread of the session is idle, however the session remains, and a further program (sometimes more accurately refered to as a sub-program) may be submitted and executed.
During execution, classes are created and objects instantiated by the program. These objects and classes persists as long as the associated session remains. Subsequent programs can access objects and classes created by previously run programs.
This persistance is ideal suited for supporting Web-based applications, in which the state of the applications must be maintained on the server.
Additionally, the use of sub-program execution matches the way in which a Web-based application handles page requests. When a page request arrives, various sub-programs are submitted and executed in order to prepare the response. The result page is returned to the waiting browser, and in the meantime the sessions execution thread is idle.
Like the Java VM, the PBVM is implemented as a Shared Library, Shared Object or Dynamic Linked Library (depending on the platform) and therefore must be "hosted" by an application in order to do it's job. Any application that supports one of the API's mentioned above will do, but general purpose applications that are programmable using PBT are of particular interest. Two such applications are provided by SNAP:PBT programs execute asyncronously and independently of programs in other sessions. The hosting application is responsible for assigning a thread for execution in each session. An application may choose to use one thread, however, in this case the application must schedule the execution in the various sessions itself.
- The PrimeBase Application Server forges a connection between the Web and the PrimeBase Virtual Machine. In particular, it connects an internet browser to a particular session in the runtime environment.
When a page is requested from the application server it translates this request into the execution of one or more PBT sub-programs. Output generated by the programs is used to generate a result page which is returned to the browser.
The mechanism used to translate pages to programs is called "LiveTags" and is discussed in detail in the PrimeBase Application Server Reference Manual.
- The PrimeBase Automation Client allows you to execute PBT programs either interactively, at scheduled times or intervals or as part of a UNIX or DOS shell script.
It also provides a "hot-foldering" mechanism which executes programs based on the arrival of files in a particaular directory. The PBAC can therefore be used for diverse automation task from routing data to send a batch of e-mails.
The unique features of PBT make it better suited for such tasks, especially database related tasks, than others languages such as Perl or Java.
Exactly how this is done depends on the API used. However, of all the API's mentioned above (DAL/DAM, ODBC, JDBC, etc.), the DAL API is the most suited to the internal workings of the PBVM, and is used by the PrimeBase Application Server and the PrimeBase Automation Client.
Other API's may limit the use of the PBT language in certain way due to limitations in their own specification. For example, the ODBC API only allows the programmer to use the SQL components of the PBT language.
Using the PrimeBase Open Server Interface, PBT can act as middleware for diverse data sources, not just the PrimeBase Database Server. The Open Server Interface is based on the client/server model and can be used for remote execution (in the form of RPC - Remote Procedure Calls) or data exchange.In order to support data transfer between a PBT program and an external data source an adaptor must be written that supports the PBOS Interface. The adaptor translates calls (SQL statements, procedure calls, etc.) from the PBVM, into calls to a 3rd Party DBMS (e.g. Oracle, Sybase etc.) or accesses data itself using, for example, XBASE or ISAM functions. Such an adaptor is compiled as a shared library and is also known as a PBOS Plug-in.
PBOS plug-ins for the most popular DBMS's are provided by SNAP, including Oracle, and ODBC data sources.
An application called the PrimeBase Open Server loads the plug-in and handles communication (local over a network) between the PBVM and the adaptor code. Alternatively a PBOS Plug-in can be loaded directly by the PBVM, eliminating the need for inter-process communication. This setup has obvious performance advantages, however, remote execution of a plug-in by the Open Server may be required for load distribution, or because as specific API required is only available on a particular machine, etc.
Whether the plug-in is loaded directly by the PBVM or loaded and hosted by the PrimeBase Open Server depends on the function of the adaptor and requirements of the system as a whole. How a plug-is deployed does not depend on how the plug-in is written, but only on the requirements of the system.
As mentioned above PBT provides a level of compatibility with the Data Access Language (DAL) from Apple™, which is also supported by previous Snap products. PBT was designed to eliminate ambiguities and add several new language features ranging from arrays to object oriented programming.To maintain compatibility and also take advantage of the new features, PBT introduces two different language modes.
- The DAL compatibility mode accepts most existing programs (with exception of some newly introduced keywords) but also supports the concepts of the new language.
- The PBT mode implements the new language with its stricter syntax and new features.
Extensions to DAL
In the following documentation, differences to the DAL mode are highlited with a special icon.
![]()
Comparison to other languages
Where appropriate, differences to other languages are also noted.
The Primebase Virtual Machine supports parallel execution through the session concept.PBVM is usually accessed by some hosting application - for example the Primebase Application Server for web-based applications. The host application can open any number of simultaneous and independently executing sessions.
![]()
There is some basic means of sharing between sessions within the same virtual machine - objects allocated during execution of the "initialize.dal" procedure file are shared. This is not recommended for complex multi-tasking purposes, as there are no synchronization mechanisms built into the language. Especially the position of cursors is also shared.
Instead, the database integration provides a superior support for persistent data, locking strategies and transactions including rollback. All of this arbitrated between any number of independent hosting applications.
This is an overview of the PrimeBaseTalk language. It will hilite the main concepts of the language and provide selected samples. Further detailed explanations and comparisons to other languages will follow in later chapters.
The hosting application has to open a connection to the PrimeBase Virtual Machine. The exact way is dependent on the API in use, and described in the "PrimeBase Virtual Machine Reference Manual". This connection is also referred to as session. The hosting application may open any number of additional independent sessions for separate execution.Usually the session setup involves specifying a database machine for the default connection, although there may none, and additional parameters for user authentification ( user name, password ).
For the PrimeBase Application Server, all of this is controlled from outside using the first entry in the file "connect.def".
In the interactive mode of the PrimeBase Automation Server, it offers a list of all available connection definitions for manual choice.
The hosting application will submit any number of PBT statements and input parameters to the PBVM using the appropriate API calls, due to prepare a subprogram invokation. The parameters are either passed as literals embedded into the program code, or sent utilizing a dedicated API call.
At the topmost level all PrimeBaseTalk subprograms are a collection of complete statements, terminated by ";". Only complete and valid statements are accepted by the compiler for one subprogram. If the compilation fails the whole subprogram is rejected.After another API call, the combination of statements and parameters is then compiled by the PBVM into its internal bytecode representation, which is then executed.
The PrimeBase Application Server provides a large choice of different points where such requests might get placed, including web page preparation and explicitly tagged page sections.
The PrimeBase Automation Server intercepts lines containing the "GO" keyword and forces execution.
The results originating from the running subprogram are returned to the hosting application by explicit PRINT and PRINTF statements. In order to receive these results, the hosting application will apply polling calls, again dependent on the used API.The PrimeBase Application Server will receive the output and deal with it according to several conventions. The simplest method will pass output into the program's own output stream.
The PrimeBase Automation Server also converts all received output to text and copies the result to its standard output.
Example
print "Hello, world"; Screen output: Hello, world
At the topmost level all PrimeBaseTalk subprograms are a collection of complete statements, terminated by ";". Although the subprogram can get transmitted using several separate API call invokations, only complete and valid statements are accepted by the compiler. If the compilation fails the whole subprogram is rejected.Besides simple statements which will get executed straight after compilation, PBT also knows statements to declare variables, procedures or whole object classes, and associate them with a name for later referral. These named entities will persist in the session across multiple different subprogram invokations, providing a convenient storage area.
The PrimeBase Application Server uses this to maintain its user session state across multiple page invokations, associated with a single user.
Most PrimeBaseTalk statements are in a functional notation similar to C and Java. For database integration, several mighty (and therefor verbose) additional statements also integrate a superset of SQL.
Any text enclosed within "/*" and "*/" is considered a comment and therefor ignored for compilation.
![]()
There is also a new provision for single line comments - text after the "//" token is skipped until the end of line.
Hint
PBT comments do nest. This makes them a partial replacement for a preprocessor as known from the C language. This approach avoids the complexity because of which the C preprocessor was omitted from the Java language.To comment out any range of code, including comments or not, just enclose it into another comment.
Hint
Some editors support balancing of brackets - exploit them inside your comments.
Example
/* { A Comment with a balanced bracket. Some inactive code here. /* an older, nested comment. */ Some more inactive code here. } */ // the closing bracket above may get found by some editors print "Hello, world.";
![]()
PrimeBaseTalk provides a rich set of primitive data types, with the speed benefit of native execution.
These include specialized types for date and time arithmetic, arbitrary size fixed point arithmetic based on BINARY coded DECIMAL (BCD) and several types for textual and BINARY data.
All primitive data types and operations support the explicit $NULL (mark) value as it is required for basic data types of relational databases.
Values of the primitive types are kept read only and therefor secured against modifications in place. All operations on them work on temporary expressions, the results have to be assigned to a variable to change it.
Literals represent a constant value of a certain data type. The characters that make up a single literal may not be separated by space, tab or end of line characters. Literal values may be placed directly in expressions and queries in PBT programs.
Besides sending literals embedded into query code, the PrimeBase VM provides dedicated API calls for direct submission of values.
Maintained at the database engine there is an additional level of data types, with stronger type checking and several additional features (case insensitive comparisons etc.) up to composite data types.
![]()
In addition to the builtin primitive data types, PBT provides native support for classes and objects, with some special classes (Array and Cursor).
All of these data types are handled using object references, in order to implement an object model comparable to Java.
Arrays are either preallocated and numerically indexed or dynamically allocated as associative array, similar to Java's Dictionary class.
Cursors are used to store result sets of database operations.
The data types are described in detail in a following section.
The PBT language is case insensitive for statements, identifiers and keywords, with identifiers having a maximum length of 31 characters.The first character of an identifier is drawn from the 26 alphabetical characters and the "_" underscore. The additionally possible "$" dollar sign is reserved for system functions.
The following identifier characters may again use the 26 alphabetical characters with addition of digits, the "#" hash mark and the "_" underscore, but not the dollar sign.
Note
The keywords "new", "this", "super" are especially reserved because they have a different meaning even inside expressions.Other keywords include "final", "abstract", "class", "extends", "public", "protected", "private" and "static".
Variables are slots used to hold any value, associated with an identifier (name). Their type is predefined at the time of declaration, making them available for further access.
![]()
PrimeBaseTalk has a new concept of dynamic constants. These are similar to traditional variables, allowing to take full advantage of all language features during initialization. From then on they are protected against changes.
With DAL, all kinds of entities shared the same global namespace. PrimeBaseTalk continues to support this global namespace, but provides alternatives.There is also a local scope during execution of procedure calls, for use by temporary "local" variables.
The local scope is shared within one procedure call - variables declared persist until exit of the procedure or explicit undeclare, even when they are declared in a contained block.
![]()
To reduce the probability of collisions in the single global namespace, PrimeBaseTalk now also supports additional namespaces, within the scope of classes.
Note
The package concept is currently not supported.
Note
Classes are declared and defined in one consecutive code sequence, similar to Java.Because of the use of classes for namespaces, the namespaces are not open for extensions.
![]()
For execution of immediate statements there is an anonymous "static" block limiting the variable lifetime of temporary variables.
![]()
SQL allows both '=' and '==' for the equality comparison, and '=' for assignments.
To resolve the ambiguity between assignment and comparison, the PrimeBaseTalk language introduces ':=' as assignment operator. Only in the DAL compatibility mode, the previously used '=' is still available.
Class members are accessed with the operator ':' instead of '->' or '::' or '.'
PrimeBaseTalk provides standard flow control for conditional execution and iteration (loops) with additional support of database specifics.
- conditional execution with IF and SWITCH statements
- iterations with WHILE, DO and FOR
- database related iterations with FOR EACH
The DAL language already supported procedural programming with some unconventional additions. These advantages persist but are integrated into a new level of object oriented programming.
- procedures might return multiple results
- parameters with either specific or generic type
- incomplete (variable length) parameter lists are permitted
Errors are handled using the traditional methods of DAL. In exceptional situations ranging from "division by zero" to "transaction timed out", an error code is made available to the handling program. Dependent on further settings, execution is returned to the program hosting the PBVM, or the session itself tries to handle the problem.A number of additional information is available through several system variables and functions.
Variables and constants are declared either in the global namespace, as member variables of classes, or dynamically during execution of procedures. These concepts are also described in detail later.The variable declaration reserves a storage area and associates it with the given name and specified data type. Variables with one data type will only accept values of this data type. Some data types are also automatically converted.
Unless given a default value on initialization, newly declared primitive type variables are tagged as "unitialized", therefor preventing use of any random value. Further explicit initialization is possible within the declaration, assigning any expression. Reference variables are initialized with the empty reference $NULL unless an explicit initialization is provided.
The value stored in a variable is available for multiple use in any expression, until it gets replaced with a new assignment or the variable gets removed - with an explicit undeclare in global or local scope, or by redeclaring it as something else with the same name.
Example
declare INT a; integer b := 1; // print a; -- would fail because a is uninitialized a := b + 1; undeclare b; // now b is gone declare VARCHAR a = "x"; // replacing old a
Named constants are not supported. Instead PBT provides a runtime protection against overriding variables declared with the final identifier. The advantage is a larger flexibility for the initialization of the constant - even from the result of a function call.Global final variables are not protected against redeclaration.
For use by variables and temporary expressions, PrimeBaseTalk supports a variety of data types which either are treated as atomic value or refer to a larger object. Data types working with concrete values are either called "primitive types" or, especially in context of relational databases, "basic types".Primitive values are "atomic" because they are not modifyable in place. A text or numeric value stored in a variable will remain the same, until the containing variable explicitly gets assigned a new value.
The primitive types have an associated numeric type code, wich is internally returned by the functions $typeof() and $coltype(), and is also used by several database related statements.
See also:
Note
The type codes used by the PrimeBase Virtual Machine are those of the CL1 API. If you access the PrimeBase Virtual Machine using a different API, for example Apple DAM or ODBC, you will encounter different type codes.$typeof(), $coltype(), printctl, describe columns, describe dbms
The following sections describe the primitive types in detail.
Note
Some extended functionalities, e.g. of domains are not supported beyond the database engine.
The BOOLEAN data type is expected by control statements like if and while.An implicit conversion to BOOLEAN is only available from integral, floating point and numeric types - textual and reference types are excluded. BINARY types have additional size constraints for a successful conversion.
The literals $false, $true and $maybe represent the different BOOLEAN values.
The BOOLEAN $maybe is mainly produced by a comparison with one of the operands being $null.
Example
print $typeof($true), $BOOLEAN; print $true, $false, $maybe; print (VARCHAR) $true, (VARCHAR) $FaLsE, (VARCHAR) $maybe; print (BOOLEAN) "$maybe" Screen output: 1 1 $TRUE $FALSE $MAYBE $TRUE $FALSE $MAYBE $MAYBE
Unlike C which uses the value zero to represent FALSE and non-zero to represent TRUE, PBT uses a special BOOLEAN type value. A BOOLEAN value can be one of 3 logical values: $true, $false or $maybe. The $maybe value is the result of a comparison with an unknown value ($null).Evulation is done according to the following logic tables:
AND $true $false $maybe $true $true $false $maybe $false $false $false $false $maybe $maybe $false $maybe
OR $true $false $maybe $true $true $true $true $false $true $false $maybe $maybe $true $maybe $maybe
NOT $true $false $false $true $maybe $maybe
Condition expressions such as those in the if, while and do statements, are only executed if the result is $true (not in the case of $false or $maybe). The conditional expression in these statements is automatically converted to a BOOLEAN value.Because of 3-valued logic used, conditional expressions can have some surprising effects. For example:
Example
procedure test(a) argument integer a; { print "Testing the value ", a; if( a==1 ) print "The value is equal to one"; if( (a==1)!=$false ) print "The value is equal to one or unknown"; if( a!=1 ) print "The value is not equal one"; if( a==1 or a!=1 ) print "The value is either equal or not equal"; else print "Two valued logic fails!"; if( a is null ) print "The value is null"; if( a is not null ) print "The value is not null"; print; } end procedure test; test(1); test(2); test($null); Screen output: Testing the value 1 The value is equal to one The value is equal to one or unknown The value is either equal or not equal The value is not null Testing the value 2 The value is not equal one The value is either equal or not equal The value is not null Testing the value $NULL The value is equal to one or unknown Two valued logic fails! The value is null
Tiny integers have the characteristics of the unsigned 8 bit integer data type know from the C language. Their value ranges from 0 to 255.
Example
tinyint t := 1; print $typeof(t), $tinyint, $len(t); print tinyint 0x7F, tinyint 0x80, tinyint 0xFF; Screen output: 20 20 1 127 128 255
Small integers are signed short (16 bit) integer ranging from -32768 to 32767.
Example
SMALLINT s = 1; print $typeof(s),$SMALLINT, $len(s); print SMINT 0x7fff, SMINT 0x8000; Screen output: 2 2 2 32767 -32768
The integer data type is equivalent to signed long (32 bit) integer ranging from -2147483648 to 2147483647.
Example
print $typeof(1),$integer, $len(1); print INT 0x7FFFFFFF, (INT 0x7FFFFFFF) + 1; Screen output: 3 3 4 2147483647 -2147483648
Hint
A 64 bit integer data type is not supported, but you can achieve even better precision and range by using the "DECIMAL" fixed point data type.
Note
In parameter matching for overloaded functions (described later), all integral types are considered equal.
Floating point values support a larger numerical range, but at the cost of less precision. This is achieved by reserving a part of the internal representation for an exponent.
Note
In parameter matching for overloaded functions (described later), all floating point types are considered equal.
A 4 byte floating point variable.
An 8 byte floating point variable.
Floating point literals are expressed in exponential form, with a DECIMAL point and a signed exponent of an 'e' or 'E'.
Example
print $smfloat, $FLOAT; print 0.123e12, 3.141E0, 100.00001e-14, -5.6789E+8; Screen output: 4 5 1.23E+11 3.141E+00 1.0000001E-12 -5.6789E+08
The fixed point variables are implemented on base of BINARY coded decimals (BCD).This means their internal representation is an almost arbitrarily long string of DECIMAL digits, two of each are squeezed into one byte value.
Hint
You can view the internal format of BCDs by converting to BINARY.
Conversion between text and fixed point is controlled by the format variables $decfmt and $moneyfmt. $moneyfmt usually includes the currency symbol.
Example
printf("%x\n",VARBIN DECIMAL[10,2] 1234.56); printf("%x\n",VARBIN DECIMAL[10,2] -1234.56); Screen output: 000123456c 000123456d
DECIMAL literals are expressed using an optional sign, digits and one contained DECIMAL point ('.').
Example
print $decfmt, DECIMAL[10,4] 1234.56; Screen output: 9,999.9 1,234.56
MONEY literals are specified with a leading dollar ('$') sign, then optional sign, digits and a DECIMAL point ('.').
Example
print $moneyfmt, MONEY[10,4] 1234.56; Screen output: $ 9,999.9 $ 1,234.56
Date values are internally represented by single bytes for date and month, and a short integer for the year. The maximum valid year is 9999 though.The $datefmt, $day, $month system variables control conversion from and to text.
In arithmetical expressions, the numeric value 1 is equivalent to one day.
Hint
By assigning partial control strings to $datefmt, you can extract any parts of the date by converting it to text.
Example
print print (date) "1/1/1999" + 1; Screen output: 01/02/1999
Time values are internally stored as one byte each for hour, minute, second and hundreths of second.The $ampm and $timefmt system control variables control conversion from and to text.
The datetime data type combines date and time into a single value.Timestamp is only an alternate name for the same data type.
Hint
The function $now() yields the current date and time. The keyword NOW is also used in the database statement CREATE DEFAULT
Date and Time constants are best submitted in their native format. If the hosting application does not support this, they must be supplied according to the currently active conversion format.The conversion format variables are accessible for read and write, therefor you can save them into a temporary variable, set them to your expected format and later on restore the value.
Example
print $datefmt; print date "1/1/1999"; Screen output: MM/DD/YYYY 01/01/1999
In addition to the direct support of textual data types, there is a rich library of string functions.Most string operations are 1 based, 1 is the position of the first character.
Hint
You can use the PBT function $format() (which is an equivalent to sprintf()) to interpret C escapes and apply formatting to additional parameters.There is also a function called PRINTF(), which uses the same parameters as $format() and which causes direct output instead of returning a string.
The maximum length of character based values, either for variables or expressions (not for database table columns!) in string operations, are as follows:
Date Type Length in Bytes Length in Characters CHAR 1 048 576 1 048 576 VARCHAR 65 536 65 536 UNICODE 1 048576 524 288
Note
The underlying database system might impose stronger restrictions on these data types!
The CHAR data type is used for fixed length strings. Shorter strings are padded with trailing spaces (ASCII character 32).For this reason trailing spaces are ignored for all string comparison operations.
Example
print $CHAR, "A" == "A "; Screen output: 9 $TRUE
Beyond the size limit of 65 535 characters for a VARCHAR, you have to use the LONGCHAR data type.Most string operations work for LONGCHAR.
Example
print $LONGCHAR; Screen output: 14
UNICODE is an ISO standard for encoding characters, with support of all written languages of the world. In version 2.0 of the UNICODE standard (version supported in PrimeBase) 16 bit encoding is used to encode up to 65 536 different characters.More information is available at www.unicode.org
The maximum length of UNICODE strings is 524 288 characters.
Example
print $typeof(UNICODE ""); Screen output: 27
Note
For correct working of the UNICODE data type, the "UNICODE" folder must be present inside the Setup folder.Some string functions ( $toupper, $tolower) currently don't expect UNICODE. They convert to VARCHAR and assume the Macintosh Roman character encoding.
Character literals are a string of characters, enclosed either in single or double quotes.The literal may contain the same quote by duplicating it, rather than escaping it with a backslash as in C.
The $format() function supports C-like escape sequences.
Example
print $format("x=%d\ny=%d\n%s",1,2,"Hello, ""YOU!"""); Screen output: x=1 y=2 Hello, "YOU!"
Literals for BINARY types are specified in hexadecimal notation which produces a VARBIN.The BINARY data types, especially VARBIN, can be used as intermediate, raw data type.
Example
print INT 0x12345678; printf("%x",VARBIN "1234"); Screen output: 305419896 31323334
The VARBIN data type is the default for short BINARY data.VARBIN is often used as intermediate data type when converting between the raw representations of incompatible data types.
Example
print $len(0x01), $typeof(0x01), $VARBIN, tinyint VARBIN "A", VARCHAR 0x40; Screen output: 1 13 13 65 @
This is the BINARY Large OBject (BLOB) variant of the BINARY data type.In database tables LONGBIN fields are stored as a separate file, with only a reference stub of 64 bytes counting into the maximum record size.
Example
print $LONGBIN; Screen output: 15
The BINARY data type is the fixed-size variant of the VARBIN data type, similar to CHAR versus VARCHAR.
Example
print $typeof(BINARY 0); printf("%x\n",BINARY[10] 4660); Screen output: 25 00001234000000000000
BINARY strings are submitted in either of two hexadecimal notations.They should contain an even number of hex digits. ( 0123456789ABCDEF )
Example
print 0x28736f6D65, 0X726177, X"6461746129"; Screen output: (some raw data)
The PBT object model is similar to Java, with some shortcuts. It is described in detail later.
- All classes are derived from the Object class.
- Multiple inheritance via interfaces or anonymous member classes is not supported.
- Objects are only accessible by reference (kind of pointer), never as direct variables.
There are no default comparison operators between object references. Currently the only legal operations are NULL tests:
Members of referenced objects are accessed using the ':' operator.
Example
class A {}; A aa = new A(); print aa is null, aa is not null;
This section covers related concepts which are not represented as own type.
Variables declared as generic are containers which accept values of any data type, both primitive and reference types.The currently assigned data type is determined by the $typeof() function.
Generic is not available as data type for database fields. You may use the VARBIN type instead, because it is generically convertible.
Null is used for two different concepts.In the context of relational databases it stands for missing (unknown) or inapplicable information. This is supported by all primitive data types.
Contrary to database fields, there is no way to declare a variable to be NOT NULL.
In the context of object oriented programs $null stands for an empty reference.
The $null constant
$null has no data type on its own (it translates to VARCHAR by default). In assignments and expressions $null is compatible with all other data types.$null only exists with the dollar sign. But for compatibility reasons, there are also some special syntactic forms originating from SQL, which require the keyword NULL instead.
Sticky NULLs
Expressions involving $null usually yield $null. Prominent exceptions are the $len() function (yields zero) and comparison operations (producing booleans).Therefor care must be taken whenever nulls could be introduced, for example through the database schema.
Example
integer i = $null; print $typeof($null), $VARCHAR, $typeof(i), i is null, $len(i), 1+$null; Screen output: 12 12 3 $TRUE 0 $NULL
The object name data type is used in database statements and when accessing cursors. It does not work as pointer to member for PBT objects.There is also no support for objname by the database engine.
Example
print $typeof(objname "name"); describe databases; fetch; print ->name, $cursor->(objname "name"); Screen output: 17 pbedemo pbedemo
In expressions, operators are used to manipulate or combine operands (variables, literals or other expressions).
The operators AND, OR and NOT operate on BOOLEAN values, and return a BOOLEAN value.Note that, unlike for example in the C programming language, both sides (operands) of the operators AND and OR are evaluated regardless of the outcome of the evaluation of the first operand. This is relevant if the calculation itself has a sideeffect, for example in a procedure call.
Example
BOOLEAN initialized = $true; BOOLEAN printed = $false; IF ( initialized AND NOT printed ) { PRINT "Now it is being printed."; } ELSE { PRINT "ERROR: Can't print, it probably has not " + "been initialized yet."; } Screen output: Now it is being printed.
The comparison operators and the "null-test" operator (IS NULL), all produce BOOLEAN values. Arguments may be values of any data type (as of PrimeBase 3.5 also CURSOR).In comparisons, if one (or both) of the operands are $null, the result is the BOOLEAN value $maybe.
Comparison operators supported by PBT are
'==', '<>', '<', '>', '<=', '>=', '!='and the unary operators IS NULL and IS NOT NULL.In addition, the DAL compatibility mode supports the equality operator '='.
Example
BOOLEAN itIsRaining = $true; IF ( itIsRaining == $true ) { PRINT "Too bad, it is raining."; } ELSE { PRINT "Hey, it is not raining."; } /* Or equivalent: */ IF ( itIsRaining ) { PRINT "Too bad, it is raining."; } ELSE { PRINT "Hey, it is not raining."; } /* And a different example: */ INTEGER anIntValue = 10; IF ( anIntValue != 10 ) { PRINT "The value has not been properly assigned " + "to the variable!"; } ELSE { PRINT "The value has been properly assigned to the " + "variable."; } Screen output: Too bad, it is raining. Too bad, it is raining. The value has been properly assigned to the variable.
Warning
Note that trailing spaces are ignored when comparing strings,
meaning that 'a ' == 'a ' evaluates to BOOLEAN true.
The following arithmetic operations are supported by PBT expressions: addition (+), subtraction (-), multiplication (*), division (/) and remainder (%).
Example
PRINT "The remainder of 10 / 3 is", VARCHAR( 10 % 3 ); Screen Output: The remainder of 10 / 3 is 1Addition operators and Date, Time
Addition of plain date and time values won't yield the intended results. Instead, the date has to be converted to a datetime.
The conversion from VARCHAR is useful to compose date and time values from their components.
Example
date d = $now(); datetime dt = d; time t = $now(); print d+t, dt+t, $now(); 02/02/1994 05/12/2000 17:34:05.00 05/12/2000 17:34:05.42String Concatenation
The addition (+) operator may also be applied to character string values. The character string values are concatenated, and the result is a VARCHAR value.
Example
PRINT "Hello" + " " + "world" + "!"; Screen Output: Hello world!
The bit-wise operations are those familiar to C and Java programmers.Shifting operators are currently not implemented.
- The BINARY bit-wise AND ( & ), bit-wise OR ( | ), bit-wise exclusive-OR ( ^ ).
- The unary bit-wise complement (~)
Example
PRINT "255 & 127 =", VARCHAR( 255 & 127 ); Screen Output: 255 & 128 = 127
PrimeBaseTalk supports extensive data type conversion. Conversion to character string values is controlled by the various Format Control Variables.Additionally there is an explicit syntax for conversion between other data types.
The following sample uses the function now() to get the current time with the type of datetime. The first cast extracts the time part, the second part converts it into a VARCHAR, using the format control variable $timefmt.
The data type used for the conversion may specify size and scale as described for the various data types.
Example
print (VARCHAR) (time) $now(); Screen output: 23:48:08.59In DAL compatibility mode the old syntax without explicit round brackets is still valid. In addition, it is not any more required to enclose the intermediate result of the first cast in brackets.
Numerical values not equal to zero are considered $TRUE in BOOLEAN promotion.
Example
print tinyint VARBIN $maybe; Screen output: 2
![]()
DECIMAL[] used to be a valid type for declarations and casts to the DECIMAL data type. Use DECIMAL[,] now to prevent collisions with the array mechanism.
Example
print (DECIMAL[10,2]) 0, DECIMAL[10,2] 0; Screen output: 0.0 0.0
The unary operators supported by PBT are unary-affirmation (+), unary-negation (-), and unary bitwise NOT (~).Permissible operands are all numeric types (TINYINT, SMINT, INTEGER, DECIMAL, MONEY, SMFLOAT, FLOAT), and BINARY values (VARBIN).
operator ++ and --
These are currently no true operators, but instead extensions of the set statement, and limited to the postfix variant.
Example
INT i = 1; set i++; i++; print i; 3
Example
/* these would all fail: ++i; print i++; MyClass:myVar++; */
Assignments change a slot referenced by some expression, on the left side of the assignment operator, to contain a new value provided by another expression, on the right side of the assignment operator.
![]()
The assignment operator has two equivalent variants: ':=' and '='.
':=' is the preferred notation required by PrimeBaseTalk mode programs. PrimeBaseTalk mode will reject the operator '='.
'=' is deprecated and only supported in DAL compatibility mode programs. It has the severe problem that the SQL language also allows the operator '=' for equality comparison. The operator ':=' is therefor recommended for DAL compatibility mode too.
Expressions using the operator = in an intermediate result are interpreting it as comparison operator.
There are no arithmetic assignment operators ( a+=7 ... ).
Example
INT a := 1; print (a = 2), a; print (a == 2), (a := 3), a; Screen output $FALSE 1 $FALSE 3 3
The '->' operator is used to access values of the current row of a CURSOR rowset. The column may be specified using the column alias, an INTEGER literal representing the column ordinal number or a variable containing one of these two.If the variable is of type INTEGER it is the column ordinal number, and if it is of type OBJNAME it is the column alias.
Example
select 1 as a, 2 as b into myCursor; fetch of myCursor; declare objname a = "b"; print myCursor->a,myCursor->:a; Screen output: 1 2
Procedures and functions allow to bind frequently used program code to a name. These are then available for execution in subsequent program code, even in the same subprogram.
Procedures are declared on a per session basis. They are not stored inside the database - the Primebase Virtual Machine does not require a database connection for its work.As with all identifiers, the name of procedures is limited to 31 characters, and case insensitive.
Hint
Procedures declared on startup of the first session, within the file "initialize.dal", are shared between all additional sessions in the same PrimeBase Virtual Machine.This feature should be avoided during development, so you don't experience replaced code.
Simple procedures have no arguments, or only arguments declared with a default. They may get invoked by simply writing their name as a statement. It is also possible to apply the more verbose syntax of complex procedures.
Unhandled results are silently ignored.
Example
PROCEDURE mySimpleProc() returns VARCHAR; { printf("Hello, world\n"); return "ABC"; } END PROCEDURE mySimpleProc;
Example
mySimpleProc; mySimpleProc(); call mySimpleProc(); Screen output: Hello, world Hello, world Hello, world
Note
It is not possible to omit the round brackets for member function calls.
In addition to the previous sample, procedures can have multiple arguments and/or multiple results.
The DECLARE keyword is optional for procedure declarations.
Example
DECLARE GLOBAL PROCEDURE myProcedure(a1,a2,a3) RETURNS VARCHAR,INTEGER; ARGUMENT VARCHAR a1 = "1"; ARGUMENT GENERIC a3 := $NULL; { PRINT "1", a1; PRINT "2", a2; PRINT "3", a3; RETURN a1,7; } END PROCEDURE myProcedure;The GLOBAL keyword is optional. It is only important when you use the "execute file" statement from within an old style global procedure. Procedures declared within that file are only temporarily available, within the scope of that procedure.
The optional RETURNS clause may declare multiple results by type. These are returned in parallel, not alternatively.
The order of the arguments in the parameter list determines the order of binding on invokation. The order may be different from the following parameter declarations.
For each parameter there can be a parameter declaration using the ARGUMENT. If a parameter is missing from the parameter declarations, it is assumed to be of type GENERIC.
In the parameter declaration, you can optionally provide a default expression. In DAL mode, both assignment operators are available for that purpose. In PBT mode (within class declarations), you have to use the ':=' operator.
Finally, you have to copy the exact procedure name into the END PROCEDURE part of the declaration.
If the parameter was declared with a default value, it is optional in the call. To skip optional parameters and override others, use an empty expression.
Example
// equivalent assuming previous procedure declaration: myProcedure(,2); myProcedure("1",2,$null);
For PBT mode subprograms (class methods) all procedures created by "execute file" are declared globally by default. Only when you use "execute file" from within DAL compatibility mode non-global procedures created there are purged, when leaving the scope of the "execute file" statement.
Example
// file myProc PROCEDURE myProc() { print "2"; } END PROCEDURE myProc; // code PROCEDURE myProc() { print "1"; } END PROCEDURE myProc; PROCEDURE aTest() { print "DAL mode"; myProc; execute file "myProc.dal"; myProc; } END PROCEDURE aTest; aTest; myProc; class X { public static PROCEDURE aTest() { print "PBT mode"; myProc; execute file "myProc.dal"; myProc; } END PROCEDURE aTest; }; X:aTest(); myProc; Screen output: DAL mode 1 2 1 PBT mode 1 2 2
Procedures with one result are allowed inside expressions.For methods, inside class declarations, there is a new alternate function declaration syntax.
Example
print mySimpleProc() + "DEF"; Screen output: Hello, world ABCDEF
![]()
It is possible to return a large number of result expressions in parallel, instead of the usual maximum of one.
This is also a alternative for the "call by reference" notation of other languages which silently modifies given parameters.
Procedures with multiple results are called with the explicit call syntax:
Example
procedure multipleReturn() returns VARCHAR, integer; { return "Test", 3; } procedure multipleReturn;
Example
generic a,b; call multipleReturn() returning a,b; print a,b; Screen output: Test 3
You can specify a matching default expression for each argument. The default is taken as a replacement value for the argument, when the calling code did not provide enough parameters or omitted the matching parameter.
Note
The default is evaluated only when no other value is specified.
Example
procedure tick() returns integer; { print "tick"; return 1; } end procedure tick; procedure timed(a1,a2) argument time a1 = $now(); argument integer a2 = tick(); { print a1; print a2; } end procedure timed; timed; timed(,2); Screen output: tick 11:06:38.84 1 11:06:38.92 2
Parameters and variables declared within procedures have a local scope. That is, they expire when the procedure is left.
![]()
Another addition to the DAL language is the introduction of static statement blocks. These fulfill two purposes:
The statements are executed in PBT mode rather than in DAL compatibility mode.
The statement block is a separate scope for variable declaration.
As you see from the example, it is possible to nest the static blocks.
Example
integer a = 1; if( $true ) static { integer a := 12; static { integer a := 123; print a; }; print a; }; print a; Screen output: 123 12 1
![]()
Note
Non-static blocks executed at global level or within other blocks of procedures or functions do not introduce a new scope.
Example
INT a = 1; if( $true ) { INT a = 2; } print a; Screen output: 2
PrimeBaseTalk provides the standard statements for flow control.
The IF statement evaluates the given expression. If the value or its BOOLEAN promotion is the BOOLEAN $true, the following statements gets executed. Otherwise an other statement after an optional ELSE keyword is executed.
Example
if( $true ) print "yes"; else print "no"; if $null is null print "yes"; else print "no"; Screen output: yes yes
The SWITCH statement evaluates the given expression, which might be of any PrimeBaseTalk primitive type, including textual types.Execution is resumed at the first CASE literal matching the value, and continues till the end of the SWITCH statement or the first BREAK encountered, whichever comes first.
The DEFAULT case is used if no direct matching literal is found. It can be located anywhere inside the SWITCH statement, even preceding further CASEs.
Neither duplicate CASEs with the same literal nor multiple DEFAULTs are permitted within one SWITCH statement.
The SWITCH statement can be used to deal with generic parameters to procedures.
Example
switch( "A" ) { case "A": print "fine"; break; case "B": print "bad"; break; case "C": print "too bad"; break; default: print "don't know"; break; case "E": print "easy"; break; ); Screen output: fine
Example
generic aValue := "A"; switch( $typeof(aValue) ) { case $CHAR: case $VARCHAR: case $LONGCHAR: print """", aValue,""""; break; default: print VARCHAR aValue; );
The LABEL statement indicates a position in code that can be addressed by the GOTO statement.The GOTO statement jumps to the statement following the LABEL statement with the same name. The label must be in current scope (procedure or global).
A GOTO statement may jump out of FOR, FOR EACH, WHILE, DO and SWITCH statement, to break the flow of execution. It is not recommended to jump into the middle of these statements.
Example
GOTO ComeHere; PRINT "A"; LABEL ComeHere: PRINT "B"; Screen output: B
The BREAK statement is used to exit the current loop (WHILE, DO, FOR, FOR EACH) or SWITCH statement.When a BREAK appears within nested loops, or SWITCH statements, it will cause the processing of the innermost loop (or rather, SWITCH) to break. It is not possible to cause a multilevel break in a single statement.
The CONTINUE statement interrupts the flow of the body of a WHILE, DO, FOR, FOR EACH statement, thus causing the remainder of the current iteration of that statement to be skipped.Execution continues with the loop control expression (for WHILE or DO) or with the loop-reinitialiser (for FOR), or with fetching of the next row (for FOR EACH).
Example
INT i; FOR( i:=1; i<5; i++ ) { if( i==3 ) continue; print i; }; Screen output: 1 2 4
The WHILE statements repeatedly evaluates the given expression. If this expression yields or is converted to $true, the next statement is executed. Otherwise the loop is ended.
Example
integer secs := 10; datetime till := $now() + secs; print "Let's sleep for", secs, "seconds!"; while( till > $now() ) { $yield(); } print "done."; Screen output: Let's sleep for 10 seconds! done.
The DO statement executes the contained statement repeatedly until the post-test evaluates to $false.
Example
BOOLEAN failed; do { failed := trySomeThing(); } while failed;
The FOR statement is used to control a loop with dependence on a control variable.The first expression in the following round brackets is an assignment used to initialize the control variable.
The second expression is the loop condition. The loop will repeat the following statement as long the second expression yields $true.
The third expression is another assignment, used to update the control variable after the following statement was executed.
Example
INT i; for( i:=0; i<2; i++ ) print i; Screen output: 0 1
The FOR EACH statements is a special loop for the result sets of database operations.Its control variable is a cursor.
Example
cursor x; describe databases into x; for each x printrow x; Screen output: Model Master
The 'errorctl' statement sets an internal control variable - execution continues after the error situation or is returned to the program hosting the PBVM.For both cases there are several system variables with further information:
- $sqlcode hold the last error code until it is reset explicitly or by a database operation.
- The $errorstring() function is available to translate an $sqlcode numeric error code into a message text.
- $sqlcode2 may contain further related error numbers - possibly platform specific error codes.
- The new $errorstack cursor describes the executing environment.
It provides the function name, if applicable, the file name and the line of the error situation.
Note
There are no Java-style exception objects.
Example
procedure toDate(aText) argument VARCHAR aText; { VARCHAR saveFmt := $datefmt; date myDate := $null; errorctl 1; // ignore following errors $datefmt = "MM/DD/YYYY"; myDate := aText; $datefmt = "MM/DD/YY"; myDate := aText; $datefmt = "D. MM. YYYY"; myDate := aText; $datefmt = "D. MMM YYYY"; myDate := aText; errorctl 0; // resume default failure mode $datefmt := saveFmt; print myDate, aText; } end procedure toDate; toDate( "25.7.1966" ); toDate( "7/25/66" ); toDate( "25. July 66" ); Screen output: 07/25/1966 25.7.1966 07/25/1966 7/25/66 07/25/1966 25. July 66
Hint
In the Primebase Enterprise Objects (PBEO) framework you find the functions PBE:try() and PBE:catch()They implement a nesting counter for the internally used errorctl function, maintain and evaluate the $sqlcode system variable.
![]()
The major new addition of PrimeBaseTalk to the previous DAL language is the introduction of object oriented programming. This is achieved by direct language support for the creation of indepenent modules, with their own variables and methods. Similar to other languages, especially C++ and Java, these modules are called classes.
A class is just another entity residing in the global namespace. It is introduced with the "class" keyword and its given name before the class declaration block which usually contains details of the class.
Example
class AB { // a very simple class };
Forward declarations allow references to not yet declared classes - for example two classes referring to each other. Of course, you should later provide the actual implementation.Forward declarations may contain the extends clause, specifying a base class.
Example
class ABC extends AB; ABC myVal;
Classes are always public. The access keywords (public, protected, private) are not applicable, as class declaration already takes place at the global namespace.Access of class members is described in the following section.
Classes can base their implementation on already declared classes. For object oriented programming this mechanism is called "inheritance". PrimeBaseTalk does not support "multiple inheritance".To inherit all public or protected properties of a class into the currently declared new class, this base class has to get mentioned in the class declaration with the optional 'extends' keyword.
All classes without explicit 'extends' automatically extend the class Object which is provided by the system.
Example
class ABC extends AB { };
Classes declared with the "final" keyword are not available for inheritance by another class. This is a very strong measure of protection, you should consider to instead explicitly make the existing methods final.
Classes declared with the "abstract" keyword can not get instantiated by themselves, but only through an inherited class.
![]()
Abstract classes don’t only allow, but require at least one abstract member function or procedure.
Example
abstract class AC1 { public abstract procedure a() end procedure a; public abstract void b(); }; abstract class AC2 { /* later */ }; /* illegal */
It is possible to redeclare an existing class with the same name at any time. This is especially useful in development of interactive systems using the PrimeBase Application Server.Existing objects survive though - they keep the association with the old class declaration. Preexisting compiled code, with parameter types of procedures and methods, also refers to the old class until recompiled. It won’t follow to redeclared classes.
Note
Although it is possible to supersede a class declaration by redeclaring the class, it is especially not recommended for the system classes.
A member is an entity contained within a class. There are storage members - variables, and executable members - procedures and functions, also commonly called methods.
The colon ":" is used for any access of class or object members. The operators "." and "->" which are used by other languages for similar purpose have a slightly different meaning:
![]()
The "." operator is used to separate table aliases in database expressions from the columns identifiers.
![]()
The "->" operator is used for cursor columns.
The "::" operator is unused.
Members declared with the keyword 'static' exist within the class rather than within single instances of that class - the objects.They are accessible from within objects similarily to non-static members, but variables share the data across all instances.
In the following sample, everything refers to one shared variable "x".
Example
class A { static INT x := 1; static void PrintX() { print x; } }; A aObj = new A(); print A:x, aObj:x; A:PrintX(); aObj:PrintX(); Screen output: 1 1 1 1
Access to the various members of a class is controlled using the modifiers 'private', 'protected' and 'public'.
- "public" grants access to everybody, including globally executed code.
- "protected" restricts the access to derived classes accessing their own inheritance.
- "private" means only the class itself can access these members.
Objects are independent instantiations of declared classes. There can be many different instances of the same class, or none.Each object has its own set of member variables, as declared in the class. Since methods can't get changed, they are efficiently shared between all objects of that class.
To create an instance of the class, the object has to be constructed by the appropriate method.Similar to other languages, this method has the same name as the class itself. For easier referral, all these creation methods are called "constructor".
The constructor as used to create an object is invoked by a special syntax - the 'new' operator.
![]()
In comparison to other object oriented languages the whole object creation process is much simplified to gain maximum speed.
- Inherited constructors are not called automatically - you have to be explicit.
- The new objects are immediately complete - calls to methods always lead to the last implementation.
- All member variables are also immediately available.
The order of these calls is not enforced by the language. You may even call to ancestor classes or call parent constructors multiple times.
Example
class A { A() { print "A"; } }; class B extends A { B() { print "B"; } }; B bb = new B(); Screen output: BThe call to the parent constructor is super:this() not, super()
To call the constructor without explicitly using the created object, you have to prefix the operator new with a colon.
Example
class C extends B { C() { print "C"; super:this(); super:super:this(); } C(INT a) { print "INT"; this(); super:this(); } }; C cc := new C(); Screen output: C B A
Example
:new C(1); Screen output: INT C B A B![]()
Inherited constructors are still available, even for derived classes.
Example
class A { A(INT x) { print x; } }; class B extends A { B() {} }; :new B(10); Screen output: 10
During class compilation, non-static member variables are also available as static variables. Both kinds of member variables can get initialized during their declaration, or in a later static code block.These assignments are evaluated only once, on class declaration. On class instantiation into an object, the values are duplicated. This is roughly equivalent to assigning a value to the prototype of a JavaScript class.
Note
If you assign references to non-static member variables, you share the referenced objects between instances of the class. To prevent this you should only preset to $NULL and initialize the members only during the constructor.
From now on, the prototype values are not accessible from outside.
Example
class Testing { public /* non-static */ INT x := 1; static { // the prototype / template gets modified x := 2; } }; /* would be a bug: Testing:x = 3; */ print new Testing().x; Screen output: 2
Member variables declared with the keyword 'final' are write once - they may even get dynamically initialized from a function result.
The finalize() callback function supports additional cleanup task when an object is reclaimed by the garbage collecting mechanism: When all references to an object are lost (reference counting) or when found unaccessible during an explicit garbage collection, an object will get purged.Similarily to Java, there is no destructor walking through the inheritance tree. Instead the special member function "finalize()" is called. An inherited super:finalize() requires an explicit call.
If the same object is again found by the garbage collection, it receives another finalize(), and so on.
Note
Instead of throwing an exception as in Java, the garbage collection can get interrupted by introducing a new reachable reference to the object, during the call to finalize().For cycles (multiple objects connected between themselves, but from nowhere else) this may lead to a situation where some objects already got finalized before one new reference is established, breaking the whole step. There is no further notice to these other objects.
The clone() member function creates a duplicate of the object. The default implementation just copies the object itself, contained references will point to the same objects. A deep copy must be performed manually.
The getClass() function yields an object representing the class. The only information currently available from class objects is the class name, via the GetName() method.
Procedures declared within a class work the same way as global procedures. In addition you may change the access using the several keywords described for class members.The separation of parameter list and parameter declaration resembles the abandoned old style of the original K&R C language.
Within class declarations, an alternate modern syntax becomes available for some methods.
Example
class MyClass { public static void anotherTest(INT x) { print x; } };
Methods declared with the 'static' modifier are accessible with and without an instance of the class. They can only access static member variables, though.
Example
MyClass obj := new MyClass(); obj:anotherTest(1); MyClass:anotherTest(1); Screen output: 1 1
Methods declared with the 'abstract' modifier are only a placeholder within an abstract class, without underlying code. The abstract class can not get instantiated into concrete objects (without inheritance) and has to be declared abstract itself.
Abstract methods are declared without the statement block. Functions require an additional ";". Procedures still require the END PROCEDURE section.
Note
An abstract class requires at least one abstract method.
Example
abstract class AClass { abstract procedure myProc() end procedure myProc; abstract void myFunc(); };
Inside one class multiple function methods may have the same identifier - they are overloaded. The functions must differ in at least one parameter type, though. The several integral types are considered to be the same - there can only be one of them. The same applies also to the different floating point types.
Overloading similarily works for non-static functions.
Example
class Over { static void load(INT a) { print "INT"; } static void load(double a) { print "FLOAT"; } static void load(VARCHAR a) { print "VARCHAR"; } static void load(UNICODE a) { print "UNICODE"; } static void load(CHAR a) { print "CHAR"; } static void load(MONEY a) { print "MONEY"; } static void load(DECIMAL a) { print "DECIMAL"; } static void load(BINARY a) { print "BINARY"; } static void load(VARBIN a) { print "VARBIN"; } static void load(LONGBIN a) { print "LONGBIN"; } }; over:load(1); over:load(SMINT 2); over:load(INT 0x12345678); over:load(DOUBLE 1); over:load(FLOAT 1); over:load(MONEY 1); over:load(DECIMAL 1); over:load(""); over:load(CHAR ""); over:load(VARBIN ""); over:load(BINARY ""); over:load(LONGBIN ""); over:load(UNICODE ""); Screen output: INT INT INT FLOAT FLOAT MONEY DECIMAL VARCHAR CHAR VARBIN BINARY LONGBIN UNICODEOverloading is only allowed for methods with the new function syntax. An attempt to overload a procedure would currently just replace it, later versions of PrimeBaseTalk will yield an error message.
It is not possible to have both static and non-static methods with otherwise similar name and parameters.
Overriding is related to inheritance: A class extends another class and therefor inherits methods from that class. When a method in the new class is declared with the same identifier and parameters as a method in the base class, it is said to override that method.When an overriden method is invoked on some object reference to the base class, the overriding code gets executed instead.
Overridden functions won't hide other functions with the same identifier, as inherited from base classes. You need not redeclare and call the inherited functions.
Example
class Base { void test() { print "test"; } }; class OverRide extends Base { void test() { print "over!"; } }; Base obj = new OverRide(); obj:test(); Screen output: over!
Example
class OverRide extends Over { static void load(VARCHAR a) { print "ride"; } }; override:load(DECIMAL 1); override:load(""); Screen output: DECIMAL ride
Instead of requiring a keyword (C++: virtual) for overridable methods, all methods are overridable by default.Only methods declared with the 'final' modifier are not available for further overriding in inherited classes. This approach is similar to Java.
Example
class A { final void ah() { print "ah"; } }; class B extends A { void ah() { print "boo"; } }; B bb = new B(); bb:ah(); Screen output: Symbol 'ah' is final. Execution Failed.
The access modifiers for class members have been discussed in the class section.
![]()
Method access rights are checked dynamically. Therefor even if you call a public method, a derived class may have overridden that method to more privacy.
Example
class A // implicitly extends Object { private void clone() {} } A aa = new A(); Object o = aa; o = o:clone(); // will fail
Reflection is the self-description of classes and