Object Ownership and Aliasing
How handles, aliasing, and object lifetimes work in the ImFusion Web SDK.
The Web SDK exposes C++ objects to JavaScript as handles. This can be surprising at first: lifetime isn't directly tied to JavaScript garbage collection, and multiple handles may refer to the same C++ object.
TL;DR
- If you construct a new SDK object, prefer
using(TypeScript explicit resource management), or calldelete()when you're done. - Use isAliasOf (not
===) to check whether two handles refer to the same underlying C++ object. - Use HandleArray (see also asHandleArray) for alias-aware
includes/indexOf/lastIndexOf.
Ownership and Lifetime
SDK objects constructed on the JavaScript side (e.g. via new or functions like
imf.createImage(...)) use shared ownership via ref-counting. Disposing a JS handle (via using
or .delete()) releases that reference; the underlying C++ object is destroyed only once no
references remain. Other SDK objects may keep additional references (for example SharedImageSet
and DataModel).
Handles to objects that are not constructed directly on the JavaScript side (e.g. returned from
imf.dataModel.get() or various load functions) are owned entirely by the C++ side and do not
require any special handling or disposal.
{
using image = imf.createImage({ ... });
} // image destroyedlet sis;
{
using image = imf.createImage({ ... });
sis = imf.createSharedImageSet([image!]);
} // image stays alive in sis
// ...
sis.delete(); // image and sis are destroyedlet sis;
{
using image = imf.createImage({ ... });
using sis = imf.createSharedImageSet([image!]);
} // image and sis are destroyed{
using image = imf.createImage({ ... });
using sis = imf.createSharedImageSet([image!]);
imf.dataModel.add(sis);
} // image and sis stay alive in dataModel
// ...
const data = imf.dataModel.get(0)!;
imf.dataModel.remove(data); // image and sis are destroyedAliasing and HandleArray
Every time an SDK function returns an object extending ClassHandle, a new handle is created by the binding layer between C++ and JavaScript. These handles wrap a pointer to the underlying C++ object. It's normal to have multiple JS handles that refer to (alias) the same underlying C++ instance.
The strict equality operator (===) tests whether the two sides are the same JavaScript object
(i.e. handle), not whether the handles refer to the same C++ object.
To test whether two handles refer to the same underlying object, use isAliasOf:
const a = imf.dataModel.get(0)!;
const b = imf.dataModel.get(0)!;
console.log(a === b); // false
console.log(a.isAliasOf(b)); // trueHandleArray
HandleArray is a normal JavaScript array with alias-aware membership methods:
includesindexOflastIndexOf
These methods treat handles as equal when they alias the same underlying C++ object.
You'll typically see HandleArray returned from SDK APIs that return handle collections, for example:
- RadiologyViewGroup.visibleData
- ImFusion loading methods like loadFileFromUrl
const plain = [loaded[0]];
plain.includes(imf.dataModel.get(0)!); // false (different JS object)HandleArray uses alias-aware membership:
loaded.includes(imf.dataModel.get(0)!); // true
imf.dataModel.includes(loaded[0]); // also trueCreating HandleArrays
Some operations produce plain arrays (e.g. spread):
const plain = [...loaded]; // Data[]If you need alias-aware membership on a plain array of handles, re-wrap it with asHandleArray:
const wrapped = imf.asHandleArray(plain);
wrapped.includes(imf.dataModel.get(0)!); // true