ImFusion Web SDK

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 call delete() 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.

ts
{
  using image = imf.createImage({ ... });
} // image destroyed
ts
let sis;
{
  using image = imf.createImage({ ... });
  sis = imf.createSharedImageSet([image!]);
} // image stays alive in sis

// ...

sis.delete(); // image and sis are destroyed
ts
let sis;
{
  using image = imf.createImage({ ... });
  using sis = imf.createSharedImageSet([image!]);
} // image and sis are destroyed
ts
{
  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 destroyed

Aliasing 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:

ts
const a = imf.dataModel.get(0)!;
const b = imf.dataModel.get(0)!;

console.log(a === b); // false
console.log(a.isAliasOf(b)); // true

HandleArray

HandleArray is a normal JavaScript array with alias-aware membership methods:

  • includes
  • indexOf
  • lastIndexOf

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:

ts
const plain = [loaded[0]];
plain.includes(imf.dataModel.get(0)!); // false (different JS object)

HandleArray uses alias-aware membership:

ts
loaded.includes(imf.dataModel.get(0)!); // true
imf.dataModel.includes(loaded[0]); // also true

Creating HandleArrays

Some operations produce plain arrays (e.g. spread):

ts
const plain = [...loaded]; // Data[]

If you need alias-aware membership on a plain array of handles, re-wrap it with asHandleArray:

ts
const wrapped = imf.asHandleArray(plain);
wrapped.includes(imf.dataModel.get(0)!); // true

On this page