08: OBP Advanced Part II: Object Keys
"Tap into Blitz3D Database Functionality."
As mentioned earlier, It has been suggested to think of Custom Types as a set of records in a Database. This analogy can be put to use and serve us well with objects. In this lesson you will learn about Object Keys and how to use them to reference individual object instances using a Pointer to Object by ID.
What is a Database Key?
By definition a Key is a field that you use to sort records. It can also be called a key field , sort key, index, or key word. For example, if you sort records by age, then the age field is a key. Most database management systems allow you to have more than one key so that you can sort records in different ways. One of the keys is designated the Primary Key, and must hold a unique value for each record. A key field that identifies records by primary key in a different table is called a Foreign Key.
Type alien Field id% ;Primary Key Field parentid% ;Foriegn Key - Parent alien's Primary Key Field x# Field y# End Type
A Object Key is a Integer Property that stores a Primary Key or Forieign Key. We use Object Keys to sort and link objects together. We conveniently label a Object Key Property with the 'ID%' suffix (A personal preference adopted from previous Database Building experience.)
In using Object Keys, we must devise a way to assign IDs and a Pointer to the Object by ID. This requires a hand-crafted ID management System. There are many ways to write a ID Management System, here I will discuss two systems I use and a few others I dont.
Manual ID Management
There two types of systems I use: A LIFO Stack and Global Index Counter.
- A LIFO Stack is ideal for managing IDs for objects that are frequently created and deleted. The IDs are Recycled. Recycling IDs ensures no IDs are wasted.
- A Global Index Counter is ideal for managing IDs for objects are created once and never deleted. The Counter is simply incremented by 1 upon the creation of a object.
For both ID assignment systems I use an Array of Object Pointers to Point to Object by ID. The array serves a pointer to a specific object instance by matching its element value to the object's primary key Value. ID and pointer assignment is handled within the Constructor and Destructor.
Global alien_ID.alien[alien_MAX%];Primary Key Object Pointer Global alien_Index%[alien_MAX%], alien_IndexPointer%;Primary Key ID Management Stack Function alienStart() ;Purpose: Initialize Class ;Parameters: TBD ;Return: None For alienloop=ALIEN_MAX To 1 Step -1; Initialize Primary Key ID Management Stack alienIndexPush(alienloop) Next End Function Function alienNew.alien() ;Purpose: CONSTRUCTOR - Creates alien Instance; Sets Default Property Values ;Parameters: TBD ;Return: alien Instance this.alien=New alien this\id%=alienIndexPop() alien_ID[this\id%]=this Return this End Function Function alienDelete(this.alien) ;Purpose: DESTRUCTOR - Removes alien Instance ;Parameters: alien Instance ;Return: None alien_ID[this\id]=Null alienIndexPush(this\id%) Delete this End Function Function alienIndexPush(alienid%) ;Purpose: Pushes ID into Primary Key ID Management Stack ;Parameters: alienid=Object's ID ;Return: None alien_Index[alien_IndexPointer]=alienid% alien_IndexPointer=alien_IndexPointer+1 End Function Function alienIndexPop() ;Purpose: Pops ID out of Primary Key ID Management Stack ;Parameters: None ;Return: Object ID% alien_IndexPointer=alien_IndexPointer-1 Return alien_Index[alien_IndexPointer] End Function
I use a Global Keyword to declare the Array of Object Pointers with [Elements], instead of Dim array(Elements). This is a Label Convention I use to separate the operation of these arrays from normal arrays. This type of array can be only one dimension and the number of elements must specified with a constant or value, no variables.
Linking Objects by ID
Object ID and Pointer to Object by ID are assigned within the Constructor and removed by the Destructor. Its relatively simple to Link Object by Objects Keys.
mother.alien=alienNew() baby.alien=alienNew() baby\parentid=mother\id mother.alien=alien_ID[baby\parentid%] mother\x#=-1.0 alien_ID[baby\parentid%]\x#=-1.0
Blitz ID Management
One might consider using Object and Handle commands. Using these commands eliminate the need for manually generating Object IDs and the use of Pointers to Objects by ID. Blitz3D internally generates a unique ID for all objects created. The Handle Command can be used to assign the ID to the Object Key, and Object Command can be used to retrieve the object from the Object Key. These commands assign and retrieve objects an unlimited number of objects, unlike using an Array of Object Pointers in the hand-crafted ID Management System.
Function alienNew.alien() ;Purpose: CONSTRUCTOR - Creates alien Instance; Sets Default Property Values ;Parameters: TBD ;Return: alien Instance this.alien=New alien this\id%=Handle(this) Return this End Function Function alienDelete(this.alien) ;Purpose: DESTRUCTOR - Removes alien Instance ;Parameters: alien Instance ;Return: None Delete this End Function
The Object Command is use to access the Properties
mother.alien=alienNew() baby.alien=alienNew() baby\parentid=mother\id mother.alien=Object.alien(baby\parentid%) mother\x#=-1.0
I prefer not to use Object and Handle commands because: 1) the commands are not officially documented Blitz3D commands; 2) Blitz3D generates IDs only at runtime. The Object ID Counter increments by one upon the creation of any object. So, the FIRST alien object created will be assigned an ID of 14, if it is the 14 object created. It will not be assigned 1 because its the first alien object created. This method of ID assignment can become cumbersome to manage in a Editing Application were object data is edited, saved, and loaded from external files.
When to use Object Pointer or Object Key as a Property?
This question will arise when developing your Objects. The're are two guidelines to help make the decision:
- If the base object has a Primary Key then make the Property a Object Key. If the base object does not have a Primary Key, use a Object Pointer.
- If the base object will provide property inheritance use a Object Pointer. If the base object is a Template use a Object Key.
Email-in this Exercise for Grade!