Object() and Handle() PrimerBlitz3D Forums/Blitz3D Tutorials/Object() and Handle() Primer
Object() and Handle() allow you to store untyped object pointers as integers. Handle() returns a unique integer for an object, while Object() will turn that integer back into a pointer to the object.
This is useful for polymorphism - code that can operate on multiple types.
It's also useful for finding the object that represents an entity. This is accomplished by storing the Handle() of your object in the entity's EntityName.
Here's a sample type we'll be playing with:
type foo field value$ end type
Before we progress, it's important to understand the distinction between pointers and objects. Objects are created via New and destroyed via Delete. Pointers are variables which can point to objects (or be Null.)
c1.foo = null c2.foo = null
Above we declared two pointers. They don't currently point to any objects.
c1.foo = foo_new("edam") c2.foo = foo_new("gouda")
Now we've created two objects and assigned our pointers to point to them. If c1 and c2 are set to Null, or fall out of scope because we return from a function, the two objects will still exist.
(When you lose your last pointer to an object, you won't be able to find that object or delete it; however, Blitz maintains its own linked-links of objects, so you'll be able to access even lost objects through its interface: Each, First, Last, Before, After.)
dim cheese.foo(10) cheese(1) = c1 cheese(2) = c2
Now we've copied our pointers into an array. There are still only two objects, but each has two pointers pointing to it: the variables c1 and c2, and the array elements in cheese(). We could call Delete(c1) or Delete(cheese(1)) and the "edam" object would be destroyed.
c1 = null c2 = null
Nothing has happened to the objects, only the pointers. Essentially, we've moved the pointers into the cheese() array.
dim foo_handle(10) foo_handle(1) = handle(cheese(1)) foo_handle(2) = handle(cheese(2))
Handle() provides an integer representation of a pointer. It can be turned back into a pointer via Object.foo(). We can now safely blow away our cheese()
cheese(1) = null cheese(2) = null
We still have two objects and two (temporarily integerified) pointers to them. Let's print our two objects's values. We do this by creating a temporary pointer to each object:
f.foo = object.foo(foo_handle(1)) print f\value$ f.foo = object.foo(foo_handle(2)) print f\value$
This will print "edam" followed by "gouda".
Finally, let's Delete our objects, once again by using temporary pointers:
f.foo = object.foo(foo_handle(1)) delete f f.foo = object.foo(foo_handle(2)) delete f
Storing handles is useful because your pointers don't have to be of a specific type. An array of type foo may only contain foo object pointers, while an integer array may contain handles to any type of object. This means you can use the same code to manipulate pointers to different types of objects.
One final note about Object():
f.foo = object.foo(foo_handle(1))
Whoops, we already deleted that object! No problem though, as the Object() command has some smarts to it. If the handle given to Object() points to a deleted object, or an object of another type than foo, Object() will return Null. You'll still have to make sure the pointer isn't Null before you use it, or you'll get a runtime error.
Note that it might not be wise to get comfortable with this functionality, as other languages don't offer this kind of safety net. The standard way to handle this kind of problem is to clean up all pointers to an object when you delete it.
| Nice one "octothorpe". |
| 2 more great contributions to the community! :) |
| Thanks Jams and "puki"! :) |
| I can't find any documentation on the Object() and Handle() commands withing Blitz. I knew they were keywords but never new what exactly they did! Does anyone know why such a fundamental thing has been left out and whether anyone has requested them to be included in a future edition of the user docs? |