Skip to content

Comments

API: Major refactoring of all codes to use a strict Interface/AbstractBaseClass, Concrete style of naming#1537

Open
imikejackson wants to merge 15 commits intoBlueQuartzSoftware:developfrom
imikejackson:topic/api_rewriting_interface
Open

API: Major refactoring of all codes to use a strict Interface/AbstractBaseClass, Concrete style of naming#1537
imikejackson wants to merge 15 commits intoBlueQuartzSoftware:developfrom
imikejackson:topic/api_rewriting_interface

Conversation

@imikejackson
Copy link
Contributor

@imikejackson imikejackson commented Feb 19, 2026

Major Refactoring of the SIMPLNX code base

The point of this PR is to create pure virtual Interfaces, Abstract classes and concreate classes where needed. Extract pure virtual where needed and create the intermediate abstract clases where needed. The entire point of this exercise is to create a clean COM style of interface for outsiders to use.

@imikejackson imikejackson marked this pull request as draft February 19, 2026 00:45
@imikejackson imikejackson force-pushed the topic/api_rewriting_interface branch 16 times, most recently from b43ee15 to 5328ed3 Compare February 20, 2026 22:09
imikejackson and others added 11 commits February 20, 2026 19:16
Phase 1: Add Code_Review/Phase1_Interface_Review.md documenting existing
interface class usage across the codebase.

Phase 2: Extract ISegmentFeatures interface from SegmentFeatures and
rename to AbstractSegmentFeatures. ISegmentFeatures defines the pure
virtual contract (execute, getSeed, determineGrouping, randomizeFeatureIds,
initializeStaticVoxelSeedGenerator) along with SeedGenerator, NeighborScheme,
and CompareFunctor types. AbstractSegmentFeatures provides the concrete
implementations and inherits from ISegmentFeatures. All subclasses
(ScalarSegmentFeatures, EBSDSegmentFeatures, CAxisSegmentFeatures) updated
to inherit from AbstractSegmentFeatures.

Also includes: IParallelAlgorithm renamed to ParallelAlgorithm, MaskCompare
utilities updates, and various algorithm fixes from the develop branch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
(cherry picked from commit 22e0b2d)
…r interface

Transform IFilter from an abstract base class into a pure virtual interface.
Create AbstractFilter to hold all concrete implementations (preflight,
execute, toJson, fromJson, defaultTags, getDefaultArguments) and the
template method pattern (preflightImpl/executeImpl). All ~300 concrete
filters now inherit from AbstractFilter. Nested types (Message,
MessageHandler, PreflightResult, ExecuteResult, etc.) remain on IFilter
as the public API contract, minimizing changes to algorithm/utility code.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add pure IPipelineNode interface defining the public contract for all
pipeline nodes (identity, operations, state queries). Signal/observer
mechanisms stay on AbstractPipelineNode since they use AbstractPipelineNode*
in callbacks. NodeType enum and RenamedPath/RenamedPaths types move to the
interface but remain accessible via inheritance.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
  New files created:
  - src/simplnx/Plugin/IPlugin.hpp - Pure interface with all 11 public methods as pure virtual (getName, getDescription, getId,
  getVendor, containsFilterId, createFilter, getFilterHandles, getFilterCount, getDataIOManagers, getSimplToSimplnxMap,
  setOocTempDirectory), plus the 6 nested types (IdType, FilterContainerType, IOManagerPointer, IOManagersContainerType, SIMPLData,
  SIMPLMapType)
  - src/simplnx/Plugin/IPlugin.cpp - Destructor-only implementation

  Files modified:
  - src/simplnx/Plugin/AbstractPlugin.hpp - Now inherits from IPlugin, removed all type aliases and SIMPLData struct (moved to
  interface, still accessible via inheritance), added override to all 11 overriding methods
  - CMakeLists.txt - Added IPlugin.hpp to both header lists and IPlugin.cpp to sources
  - src/Plugins/SimplnxCore/wrapping/python/simplnxpy.cpp - Added IPlugin include, pybind11 binding, and registered AbstractPlugin as
  inheriting from IPlugin

  Files requiring NO changes:
  - All 8 plugin classes (SimplnxCore, OrientationAnalysis, ITK, TestOne, TestTwo, SimplnxReview, TestPlugin, PythonPlugin) - they
  inherit AbstractPlugin, no change needed
  - PluginLoader, FilterList, Application, Preferences - use AbstractPlugin* which still works
  - CreatePluginFunc/DestroyPluginFunc typedefs and SIMPLNX_DEF_PLUGIN_IMPL macro - stay on AbstractPlugin.hpp
  - All DREAM3DNX files - use AbstractPlugin*
…interfaces

Renamed 6 geometry classes from I* to Abstract* prefix and extracted
standalone pure virtual interfaces above them:
- IGeometry → AbstractGeometry (+ new IGeometry interface)
- IGridGeometry → AbstractGridGeometry (+ new IGridGeometry interface)
- INodeGeometry0D-3D → AbstractNodeGeometry0D-3D (+ new interfaces)

Interfaces are standalone (no inheritance hierarchy) to avoid diamond
inheritance. Type aliases, enums, and string constants live on the
interfaces so scope resolution (e.g. IGeometry::Type) works unchanged.
k_TypeName strings preserved for serialization compatibility.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Created IDataStructure pure virtual interface with all non-template
public methods from DataStructure. DataStructure now inherits from
IDataStructure with override on all implemented methods. Template
convenience methods (getDataAs, getDataRefAs, etc.) remain on
DataStructure only since C++ templates cannot be virtual.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…diagram

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nterfaces

Move concrete method implementations from IDataStore (getSize, size,
empty, getDataFormat) and IListStore (size) down to their respective
Abstract* template classes. All three interfaces now have only pure
virtual methods. Updated class hierarchy diagram and review document.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move toJson(), fromJson(), construct() implementations and
toJsonImpl()/fromJsonImpl() template-method hooks from IParameter
down to AbstractParameter. IParameter is now a pure interface with
14 pure virtual methods and zero concrete methods.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ect hierarchy

- Extract IArrayThreshold pure interface, rename old class to AbstractArrayThreshold
- Refactor IJsonPipelineParser to pure interface, create AbstractJsonPipelineParser
- Rename IArray -> AbstractArray (k_TypeName "IArray" preserved for serialization)
- Rename IDataArray -> AbstractDataArray (k_TypeName "IDataArray" preserved)
- Rename INeighborList -> AbstractNeighborList (k_TypeName "INeighborList" preserved)
- Update DataObject::Type enum members (numeric values unchanged)
- Update Phase_8_Interface_Review.md and Phase_8_Class_Hierarchy.dot
- All 1106/1107 tests pass (1 expected failure: ExecuteProcessFilter)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… remove dead JSON code

Phase 12: Renamed IDataIOManager to AbstractDataIOManager across 14 source files
and CMakeLists.txt. The class has 3 data members, ~9 concrete methods, and only
1 pure virtual (formatName()), so it is an abstract base class, not a pure interface.

Phase 13: Removed the dead src/simplnx/Utilities/Parsing/JSON/ directory (15 files)
which was not compiled (absent from CMakeLists.txt) and not referenced from any
compiled source.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
imikejackson and others added 3 commits February 20, 2026 19:17
…lasses

Add IArray, IDataArray, and INeighborList as aliases for AbstractArray,
AbstractDataArray, and AbstractNeighborList in the Python bindings so
existing scripts continue to work.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…o AbstractDataObject

Extract IDataObject pure interface (21 pure virtual methods) from DataObject,
rename DataObject to AbstractDataObject, update all references across simplnx,
external plugins (FileStore, Synthetic), and DREAM3DNX. Add backwards-compatible
Python alias for DataObject.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@imikejackson imikejackson force-pushed the topic/api_rewriting_interface branch from 5328ed3 to 284b797 Compare February 21, 2026 00:17
@imikejackson
Copy link
Contributor Author

Phase 15 Summary: Fix I-Prefix Naming Violations

Phase 15 completes the COM-style naming convention cleanup. All I-prefixed classes are now true pure interfaces — classes that had data members or concrete methods have been renamed to Abstract*.


Part A: Renamed 8 I-prefixed non-interfaces → Abstract*

These classes used the I prefix but were not pure interfaces (they had data members, concrete method bodies, or static helpers):

Old Name New Name Scope
IDataCreationAction AbstractDataCreationAction 31 files, ~64 occurrences
IDataIO AbstractDataIO File rename + class rename
IGeometryIO AbstractGeometryIO File rename + class rename
IGridGeometryIO AbstractGridGeometryIO File rename + class rename
INodeGeom0dIO AbstractNodeGeom0dIO File rename + class rename
INodeGeom1dIO AbstractNodeGeom1dIO File rename + class rename
INodeGeom2dIO AbstractNodeGeom2dIO File rename + class rename
INodeGeom3dIO AbstractNodeGeom3dIO File rename + class rename

Part B: Promoted AbstractStringStore → IStringStore

AbstractStringStore had no data members and 12 pure virtual methods. Its only concrete methods were trivial iterator/comparison helpers delegating to pure virtuals. By project convention, it qualifies as a pure interface and was renamed to IStringStore.


Applied Across Repositories

  • simplnx: 84 files changed (HDF5 IO classes)
  • FileStore: 44 files changed (Zarr IO equivalents)
  • Python bindings: Backwards-compatible alias added for IDataCreationAction

Post-Rebase Fixes

After rebasing onto the latest develop branches, several conflicts were resolved:

  • StatusCodeResult<>: The develop branch changed geometry method return types from StatusCode to Result<>. Updated 4 Abstract geometry headers to match the new interface signatures.
  • Constructor initializer lists: 7 concrete geometry .cpp files had constructor calls reverted to old I* names during rebase — fixed back to Abstract*.
  • Constant qualifications: Fixed INodeGeometry2D::k_SharedEdgeListNameINodeGeometry1D::k_SharedEdgeListName (3 files) and INodeGeometry3D::k_SharedFacesListNameINodeGeometry2D::k_SharedFacesListName (2 files) — the standalone interfaces don't inherit from each other.
  • getDataRefAs<IGeometry>: Fixed to getDataRefAs<AbstractGeometry> in ComputeFeatureSizes (2 files) — IGeometry is now a standalone interface, not part of the AbstractDataObject hierarchy.
  • ComputeFeatureSizesFilter: Restored RectGrid to the allowed geometry types (lost during rebase conflict resolution).
  • RectGridGeom::checkUpdatedIdsImpl: Fixed call from IGridGeometry:: to AbstractGridGeometry::.

Test Results

simplnx-Rel: 1060/1062 pass

  • 1 expected failure: ExecuteProcessFilter (sandbox environment)
  • 1 pre-existing rebase issue: 6.6 Mega Pipeline Conversion (MergeColoniesFilter parameter key mismatch in SIMPL JSON conversion — unrelated to Phase 15)

Documentation Updated

  • Code_Review/Phase_8_Interface_Review.md — Updated class entries, hierarchy tree, and naming convention table
  • Code_Review/Phase_8_Class_Hierarchy.dot — Updated node names and colors
  • CLAUDE.md — Phase 15 checkboxes marked complete

Current Interface Count

22 pure interfaces (up from 21 after Phase 14):
IFilter, IPlugin, IPipelineNode, IDataObject, IDataStructure, IGeometry, IGridGeometry, INodeGeometry0D3D, ISegmentFeatures, IMaskCompare, IJsonFilterParser, IPluginLoader, IDataStore, IListStore, IDataFactory, IParameter, IArrayThreshold, IJsonPipelineParser, IStringStore

@imikejackson imikejackson marked this pull request as ready for review February 21, 2026 00:25
@imikejackson imikejackson force-pushed the topic/api_rewriting_interface branch from 284b797 to b19af99 Compare February 21, 2026 00:26
@imikejackson
Copy link
Contributor Author

Complete Summary of Name Changes in This Branch

This branch enforces a strict COM-style naming convention across the entire codebase:

  • I prefix = pure virtual interface (no data members, no concrete methods)
  • Abstract prefix = abstract base class (has data members and/or concrete implementations)
  • No prefix = concrete class

Classes Renamed (Old → New)

Phase 2

Old Name New Name
SegmentFeatures AbstractSegmentFeatures
IParallelAlgorithm ParallelAlgorithm

Phase 3

Old Name New Name
IFilter AbstractFilter

A new pure interface IFilter was extracted from the old IFilter (which had concrete methods and was therefore an ABC, not an interface).

Phase 6

Old Name New Name
IGeometry AbstractGeometry
IGridGeometry AbstractGridGeometry
INodeGeometry0D AbstractNodeGeometry0D
INodeGeometry1D AbstractNodeGeometry1D
INodeGeometry2D AbstractNodeGeometry2D
INodeGeometry3D AbstractNodeGeometry3D

New pure interfaces IGeometry, IGridGeometry, INodeGeometry0D3D were extracted from each.

Phase 10

Old Name New Name
IParameter (near-pure) AbstractParameter (base class portion)

IParameter was promoted to a true pure interface; concrete methods moved to AbstractParameter.

Phase 11

Old Name New Name
IArray AbstractArray
IDataArray AbstractDataArray
INeighborList AbstractNeighborList
IArrayThreshold AbstractArrayThreshold
IJsonPipelineParser AbstractJsonPipelineParser

New pure interfaces IArrayThreshold and IJsonPipelineParser were extracted from the old classes of the same name.

Phase 12

Old Name New Name
IDataIOManager AbstractDataIOManager

Phase 14

Old Name New Name
DataObject AbstractDataObject

A new pure interface IDataObject was extracted.

Phase 15

Old Name New Name
IDataCreationAction AbstractDataCreationAction
IDataIO AbstractDataIO
IGeometryIO AbstractGeometryIO
IGridGeometryIO AbstractGridGeometryIO
INodeGeom0dIO AbstractNodeGeom0dIO
INodeGeom1dIO AbstractNodeGeom1dIO
INodeGeom2dIO AbstractNodeGeom2dIO
INodeGeom3dIO AbstractNodeGeom3dIO
AbstractStringStore IStringStore

New Pure Interfaces Created

These are brand-new classes extracted during the refactoring:

Interface Extracted From Phase
IFilter old IFilter (now AbstractFilter) 3
ISegmentFeatures SegmentFeatures (now AbstractSegmentFeatures) 2
IPipelineNode AbstractPipelineNode 4
IPlugin AbstractPlugin 5
IGeometry old IGeometry (now AbstractGeometry) 6
IGridGeometry old IGridGeometry (now AbstractGridGeometry) 6
INodeGeometry0D old INodeGeometry0D (now AbstractNodeGeometry0D) 6
INodeGeometry1D old INodeGeometry1D (now AbstractNodeGeometry1D) 6
INodeGeometry2D old INodeGeometry2D (now AbstractNodeGeometry2D) 6
INodeGeometry3D old INodeGeometry3D (now AbstractNodeGeometry3D) 6
IDataStructure DataStructure 7
IArrayThreshold old IArrayThreshold (now AbstractArrayThreshold) 11
IJsonPipelineParser old IJsonPipelineParser (now AbstractJsonPipelineParser) 11
IDataObject DataObject (now AbstractDataObject) 14

IParameter, IStringStore, IDataStore, IListStore, and IDataFactory were existing classes promoted/confirmed as pure interfaces (Phases 9, 10, 15).


Python Backwards-Compatible Aliases

The following aliases were added to the Python bindings so existing scripts continue to work:

simplnx.DataObjectsimplnx.AbstractDataObject
simplnx.IArraysimplnx.AbstractArray
simplnx.IDataArraysimplnx.AbstractDataArray
simplnx.INeighborListsimplnx.AbstractNeighborList
simplnx.IDataCreationActionsimplnx.AbstractDataCreationAction

Dead Code Removed

  • src/simplnx/Utilities/Parsing/JSON.deprecated/ — 15 files, not compiled or referenced anywhere (Phase 13)

Serialization Compatibility

All renamed geometry classes preserve their original k_TypeName string values (e.g., AbstractGeometry::k_TypeName = "IGeometry") to maintain backward compatibility with existing .dream3d files.

…mote AbstractStringStore to IStringStore

Part A: Renamed 8 misnamed I-prefixed classes to Abstract*:
- IDataCreationAction → AbstractDataCreationAction (Output.hpp + 31 files)
- IDataIO → AbstractDataIO (file rename + class rename)
- IGeometryIO → AbstractGeometryIO (file rename + class rename)
- IGridGeometryIO → AbstractGridGeometryIO (file rename + class rename)
- INodeGeom0dIO → AbstractNodeGeom0dIO (file rename + class rename)
- INodeGeom1dIO → AbstractNodeGeom1dIO (file rename + class rename)
- INodeGeom2dIO → AbstractNodeGeom2dIO (file rename + class rename)
- INodeGeom3dIO → AbstractNodeGeom3dIO (file rename + class rename)

Part B: Renamed AbstractStringStore → IStringStore (no data members, pure interface)

Applied same renames to FileStore plugin (Zarr IO equivalents).
Added backwards-compatible Python alias for IDataCreationAction.
All 1106/1107 tests pass (1 expected failure: ExecuteProcessFilter).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@imikejackson imikejackson force-pushed the topic/api_rewriting_interface branch from b19af99 to b741182 Compare February 21, 2026 00:32
@imikejackson imikejackson changed the title API: Major refactoring of all codes to use a strict COM style of Interface/AbstractBaseClass, Concrete Class API: Major refactoring of all codes to use a strict Interface/AbstractBaseClass, Concrete style of naming Feb 24, 2026
@imikejackson
Copy link
Contributor Author

Comments from the requestor

Again the objective is to have a better separation between the host projects and the plugins. It is also to allow using a plugin built independently from any host application and most often after the host application. You could make a new plugin and send it to another team without having to provide a new host application. So we would use explicit linkage in the host using def files to alias the exports. We cannot rely on the decorated names because the name mangling is compiler dependent.

An interface looks like:

struct PrgniFace0
{
   virtual void func0() = 0;
   virtual int64_t func1(int v0, int v1) = 0;
   virtual double func2(double v0) = 0;
};

This would be in an header file shared by both host projects and plugins. To be clear, the interface header file is shared not exported. It is included in all projects supporting this interface. The interface is clean from any proprietary types and thus can be included in projects without having to pull any other proprietary includes. A plugin can support multiple interfaces.

The plugin then implement a regular class derived from that interface and any other interfaces it needs to support. That class is not exported either. This class implements all the functions from the interface. This implementation class can also have data members. It can also handles any types, proprietary or not.

The plugin then provides a class factory. This is the only export of the plugin which would look something like this:

Header file:

#pragma once
 
#include <prgniface0.h>            // supported interface
#include "prgnpi0_global.h"     // dll export definition
 
extern PRGNPI0_EXPORT std::shared_ptr<PrgniFace0> GetPrgniFace();

This header file is not shared with host applications but the class factory is exported, PRGNPI0_EXPORT. Host applications rely on the export symbol to be the same in every plugins.

Source file:

#include <memory>
#include <qdebug.h>
#include "FilterFactory.h"
#include "Prgnpi0.h"
 
std::shared_ptr<PrgnPI0> pFilter;
 
std::shared_ptr<PrgniFace0> GetPrgniFace()
{
    if (pFilter == nullptr)
    {
        pFilter = std::make_shared<PrgnPI0>();
    }
    std::shared_ptr<PrgniFace0> p = std::dynamic_pointer_cast<PrgniFace0, PrgnPI0>(pFilter);
    return p;
}

The “std::dynamic_pointer_cast” will not only upcast to the parent interface class, it will also properly handle the reference count.

Using the plugin in a host application look like this:

    QLibrary lib;
    QString path = "prgnpi0.dll";
 
    qApp->addLibraryPath(".");
    lib.setFileName(path);
    lib.load();                                        // Loads the library
    if (lib.isLoaded())
    {
        qDebug() << "\nLibrary " << path.toStdString().c_str() << " loaded\n";
    }
    else
    {
        qDebug() << "\nError " << lib.errorString() << "\n";
    }
 
    typedef std::shared_ptr<PrgniFace0>(__cdecl* GetiFace)();
    GetiFace pGetPrgniFace = reinterpret_cast<GetiFace>(lib.resolve("GetPrgniFace"));  // gets the class factory
    if (pGetPrgniFace)
    {
        std::shared_ptr<PrgniFace0> p = pGetPrgniFace();  // invoke class factory to get the interface
        if (p)
        {
            qDebug() << "Found interface PrgniFace0\n";
 
           // use the interface
            p->func0();
            int iVal = p->func1(2, 5); 
            double dVal = p->func2(2);
               
            qDebug() << iVal << " ," << dVal << "\n";
        }
        else
        {
            qDebug() << "Cannot find interface PrgniFace0\n";
        }
    }
    else
    {
        qDebug() << "\nError: Unable to resolve GetPrgniFace0\n";
    }

Thia scheme is loosely based on the Component Object Model, COM, from Microsoft.

@imikejackson
Copy link
Contributor Author

Analysis of the requestor's code

What it describes

The section lays out a COM-inspired plugin architecture where:

  1. Pure virtual interfaces (structs with = 0 methods) are shared as headers between host apps and plugins — no exported symbols,
    no proprietary types.
  2. Concrete implementations derive from those interfaces but are not exported — they're internal to the plugin.
  3. A single class factory function (e.g., GetPrgniFace()) is the only exported symbol from each plugin. It constructs the
    concrete class and returns it upcast to the interface via std::dynamic_pointer_cast.
  4. The host app dynamically loads the plugin (via QLibrary/dlopen), resolves the factory symbol by name, calls it, and gets back
    a shared_ptr to work through.

Strengths of the description

  • The motivation is clearly stated: decouple plugins from the host so they can be built and distributed independently, even
    after the host ships.
  • The full roundtrip is shown — interface definition, implementation, factory, and host-side loading/usage — which makes the
    intent unambiguous.
  • The explicit mention of avoiding decorated/mangled names and using def files for explicit linkage shows awareness of the key
    cross-compiler ABI pitfall.

Things worth noting / potential concerns

  1. extern "C" is missing from the factory. The example declares extern PRGNPI0_EXPORT std::shared_ptr
    GetPrgniFace(); but doesn't use extern "C". Without it, the symbol name is still mangled, which undermines the stated goal of
    compiler-independent symbol resolution. The mention of "def files to alias the exports" is the workaround, but extern "C" is
    simpler and more portable.
  2. Returning std::shared_ptr across DLL boundaries is fragile. If the host and plugin are built with different compilers or even
    different STL versions, the std::shared_ptr layout may differ. COM solves this by returning raw interface pointers and using
    AddRef/Release for reference counting. If true cross-compiler compatibility is a goal, returning a raw pointer (or a COM-style
    IUnknown-like base) and managing lifetime through the interface itself would be safer.
  3. The singleton pattern in the factory (static-like pFilter global) means every call to GetPrgniFace() returns the same
    instance. This may be intentional (single plugin instance) but it prevents multiple independent instances of the same filter,
    which could limit pipeline parallelism.
  4. Virtual interface + no virtual ~Destructor: The example PrgniFace0 struct has no virtual destructor. Destroying through a
    base pointer would be undefined behavior. This is likely just an oversight in the example, but worth calling out since it's a
    classic C++ pitfall.
  5. Qt dependency in the host-side loading code (QLibrary, qDebug): The host example uses Qt for dynamic loading. If the goal is
    maximum portability, abstracting over dlopen/LoadLibrary might be preferable — though Qt may already be a given dependency in
    DREAM3DNX.

Relationship to the refactoring work already done

Looking at the memory notes (Phases 1–15), the project has already done extensive work extracting pure interfaces (IFilter,
IPlugin, IGeometry, IDataStructure, IParameter, IDataStore, etc.) from their concrete implementations. This aligns directly with
step 1 of the architecture described in the CLAUDE.md — having clean interface headers that can be shared without pulling in
proprietary types. The ground has been well prepared for this plugin model.

Summary

The architecture is sound for the stated goal — it's a proven pattern (essentially COM-lite). The main gaps in the description
are around ABI safety (extern "C", shared_ptr across boundaries, virtual destructors) which are implementation details that
would need to be addressed when actually building it out. The existing refactoring work (extracting I* interfaces) has already
laid most of the foundation for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant