IVersioned class

Basic interface, from which all specialized interfaces descend.

For more information about using the OO API to access Firebird databases, please refer to the doc/Using_OO_API.html document in the official Firebird installation.

Technical notes.

All interfaces in the OO API extend (directly or indirectly) the IVersioned interface. Both IDisposable and IReferenceCounted base interfaces also extend IVersioned, therefore IVersioned's memory layout implies the inner layout of all interface objects.

The IVersioned native interface in libfbclient consists of a dummy CLOOP field (a single pointer to be ignored) and a pointer to the VTable, i.e. an array of method pointers. The VTable is the heart of an interface, because it is the only way to access the interface's functionality (its methods).

Note: this philosophy resembles somewhat the Windows COM model.

A pointer to an interface returned by any libfbclient routine, which is declared as returning an interface object, should be treated (as long as the interface extends IVersioned) as an array of two consecutive pointers, from which only the second pointer is actually of any value, because it points to the VTable of the interface:

((uintptr_t*) IVersioned)[0] - ignore: CLOOP dummy pointer ((uintptr_t*) IVersioned)[1] - points to the VTable of the interface

The relevant snippet from the IVersioned C++ implementation (include/firebird/IdlFbInterfaces.h):

class IVersioned
{
public:
	struct VTable
	{
		void* cloopDummy[1];
		uintptr_t version;
	};

	void* cloopDummy[1];
	VTable* cloopVTable;

However, the original pointer to the interface has to be retained, because methods of the interface require the interface pointer (and not the interface's VTable pointer) to be passed as the first argument. In other words, we invoke functions, which come from the VTable, but the functions receive (as their first argument) not the VTable as such, but an interface pointer, from which VTable can be further obtained (as the second pointer counting from the beginning of the interface).

Every interface extending IVersioned (which at this moment means every interface from libfbclient OO API) on the Dart side is constructed in the following way. The Dart class, wrapping the Firebird interface, has the following attrbutes:

  • startIndex - defines the first index (slot) in the VTable, which contains a method of this particular interface (all slots with lower indices contain methods of ancestor interfaces); this attribute is calculated as startIndex + metodCount of the parent interface (except of IVersioned, for which those are constant, because it's the ancestor of all other versioned interfaces),
  • methodCount - defines the number of VTable slots, which this particular interface occupies.

Therefore, if we have an interface hierarchy: A <- B <- C (B extends A, and C extends B), their attributes are defined as:

  • A.startIndex and A.methodCount are constant (A.startIndex is most likely 0),
  • B.startIndex = A.startIndex + A.methodCount,
  • B.methodCount is constant (specific to interface B),
  • C.startIndex = B.startIndex + B.methodCount,
  • C.methodCount is constant (specific to interface C).

The calculation of startIndex in terms of the superclass' attributes and the definition of methodCount are both placed in the class constructor. That's because fbclient is supposed to support different versions of the Firebird interfaces, and in the future the values of methodCount will depend on the version of the interface.

Additionally, each interface defines (overrides) the method minSupportedVersion, which return the minimal required interface version number. If a Dart object, created around a native Firebird interface pointer, detects that the native interface has a version lower than the minimum required (which can mean not all methods, which the Dart class constructor will attempt to map, may be present in the interface's VTable), an exception is thrown. Note, that receiving a higher interface version should be safe (as long as there are no descendant interfaces), the worst that can happen is that some new methods from the VTable won't be available in the Dart class.

The VTable layout of an example interface (IMetadataBuilder version 4, extending IReferenceCounted, which extends IVersioned):

[0]: IVersioned.CLOOP dummy pointer (to be ignored)
[1]: IVersioned.version number (from IVersioned)
[2]: IReferenceCounted.addRef method pointer
[3]: IReferenceCounted.release method pointer
[4]: IMetadataBuilder.setType method pointer
...
[17]: IMetadataBuilder.setAlias method pointer

In version 4, IMetadataBuilder has 14 methods (VTable[4] ... VTable[17]).

Implementers

Constructors

IVersioned(FbInterface self)

Properties

hashCode int
The hash code for this object.
no setterinherited
methodCount int
The number of entries in the VTable the interface occupies.
getter/setter pair
runtimeType Type
A representation of the runtime type of the object.
no setterinherited
self FbInterface
The raw pointer to the native interface.
getter/setter pair
startIndex int
The first entry in the VTable the interface uses.
getter/setter pair
version int
The interface version. Copied from the VTable for convenience.
getter/setter pair
vtable FbInterface
The pointer to the interface's VTable.
getter/setter pair

Methods

minSupportedVersion() int
Defines the minimum native interface version supported by this class in fbclient.
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
toString() String
A string representation of this object.
inherited

Operators

operator ==(Object other) bool
The equality operator.
inherited