We think multiple inheritance just needed consistent ordering. The problem of how dependencies combine, how objects inherit, how configurations cascade, and how methods meld gets simpler when you use the same algorithm for everything.
Rather than having separate, inconsistent composition rules, we've found it works better to use a single, reusable algorithm that each system adapts to its specific needs. Whether working with Package dependencies, Pattern inheritance, Pod configuration cascading, or Module loading, the same fundamental 4-phase resolution process has worked well for us—each system implements it with specialized logic for their particular composition requirements.
The resolution system handles multi-source composition through these capabilities:
These capabilities solve the problems of composition once, creating a reusable framework with consistent behavior regardless of whether you're composing packages, patterns, configurations, or modules.
The universal composition algorithm operates through four phases that transform multi-source relationships into predictable, linear sequences:
This systematic approach ensures that composition scenarios—which would otherwise require manual orchestration—become predictable and automatically managed. The key insight is that explicit dependency relationships and prerequisites drive ordering first, then conditions filter what actually gets applied; ambiguity is minimized through clear declarations rather than relying on implicit "last wins" semantics.
Design Principle: Predictable composition comes from explicit relationships, not implicit rules. Define prerequisites clearly to ensure deterministic outcomes.
While the core 4-phase algorithm remains consistent, each system implements it with specialized behaviors:
Pattern resolution applies the algorithm multiple times in sophisticated ways:
Pattern resolution operates across multiple composition domains simultaneously.
Pod resolution implements the algorithm for cascading deep merges:
~~key
syntax for explicit removal follows resolution orderPermission resolution enables group merging with composition logic:
~~permission
syntax for explicit denialModule resolution focuses on execution order and parameter injection:
The same composition approach applies across all Doh systems, demonstrating how a single, well-designed solution can handle diverse composition requirements.
The Load System demonstrates the resolution approach solving dependency orchestration—ensuring resources are available in the correct order across different environments and loading contexts.
The universal composition system handles dependency loading through Doh.expand_dependencies
, which transforms complex dependency declarations into ordered loading sequences:
Doh.expand_dependencies = function(dep, packages = Doh.Packages) {
// Applies the universal resolution system to dependency trees
// Recursively expands to ensure correct load order
}
This implementation is accessed through Doh.load()
, which serves as the declarative interface to the underlying composition system:
// Load a single dependency
Doh.Module('myModule', ['dependency-name'], function(export_from_dep){
// module code here.
});
const exported_stuff = await Doh.load('dependency-name');
// Load multiple dependencies
Doh.Module('myModule2', ['dep1', 'dep2', 'dep3'], function (dep1Global, dep3Global){
const exports_from_dep1 = dep1Global;
const efd3Prop = efd3Global.efd3Prop;
})
const [exports_from_dep1, , { efd3Prop }] = await Doh.load(['dep1', 'dep2', 'dep3']);
Doh.Module('FeatureModule', [
'core', // Loaded first (and its dependencies)
'await database', // Loaded next and waited for
'async utilities', // Started loading in parallel
'browser?? ui-tools' // Conditionally loaded in browser environments
], function(shared) {
// Module implementation
});
The resolution system ensures these dependencies are loaded in the correct order, respecting both explicit decorators and implicit dependencies.
The Pod system demonstrates the resolution approach solving configuration inheritance—ensuring that settings from multiple sources combine predictably to create coherent, hierarchical configuration systems.
The universal composition system handles configuration cascading through build_pod
, which applies the same resolution principles to hierarchical settings:
Doh.build_pod = async function(podLocation) {
// Applies universal resolution system to configuration inheritance
// Merges multiple configuration sources into coherent hierarchy
}
# pod.yaml
inherits:
- base_config.yaml
- environment/development.yaml
- feature/authentication.yaml
# Custom overrides
database:
host: localhost
port: 5432
Resolution order:
base_config.yaml
(and its inheritance chain)environment/development.yaml
(and its inheritance chain)feature/authentication.yaml
(and its inheritance chain)The Pattern system provides the most multi-layered implementation of resolution order, applying the algorithm across multiple composition domains simultaneously.
The Pattern resolution is implemented through:
Doh.extend_inherits = function(inherits, skip_core = false) {
// Expands the inheritance tree
}
Doh.resolve_inherits_hardening = function(extended, inherits, skip_core) {
// Resolves conditional inheritance and hardening
}
Hard Inheritance (true): Pattern will always be included
inherits: {
BasePattern: true // Always included
}
Soft Inheritance (false): Pattern will only be included if required elsewhere
inherits: {
OptionalPattern: false // Conditionally included
}
Conditional Inheritance (object): Pattern will be included based on complex conditions
inherits: {
ConditionalPattern: { // Included only if DepPattern is also included
DepPattern: true
}
}
Pattern('AdvancedComponent', {
inherits: {
BaseComponent: true, // Hard inheritance
UIComponent: true, // Hard inheritance
DraggableComponent: false, // Soft inheritance
ResizableComponent: { // Conditional inheritance
DraggableComponent: true // If ResizableComponent is included, include DraggableComponent
}
}
});
Pattern('SpecializedComponent', 'AdvancedComponent', {
inherits: {
ResizableComponent: true // Hard inheritance, triggers conditional inheritance
}
});
Resolution for SpecializedComponent
:
object
(implicit base)BaseComponent
UIComponent
DraggableComponent
(included due to ResizableComponent)ResizableComponent
AdvancedComponent
SpecializedComponent
Modules combine dependency resolution with execution order management.
Module loading is handled by Doh.Module()
, Doh.Package()
, and Doh.load()
:
// Load a module
// as a dep:
Doh.Package('someModule', {
load: ['module-name']
});
Doh.Module('anotherModule', ['module-name'], function(some_import_or_global){
//module code
});
// or inline
await Doh.load('module-name');
// Load multiple modules
// as a dep:
Doh.Package('someModule', {
load: ['module1', 'module2']
});
Doh.Module('anotherModule', ['module1', 'module2'], function(some_import_or_global){
//module code
});
// or inline
await Doh.load(['module1', 'module2']);
The module resolution order affects:
How these separate systems interact is what makes Doh's resolution system work:
const myComponent = New('SpecializedComponent', {
// Properties
});
The pattern resolution order controls:
Doh.Module('UIModule', ['BaseComponents'], function() {
// Can safely use patterns defined in BaseComponents
Pattern('CustomButton', 'Button', {
// Button is defined in BaseComponents
});
});
# In pod.yaml
DatabaseModule:
connection:
host: production-db.example.com
These configurations are accessible in modules:
Doh.Module('DatabaseModule', function() {
const config = Doh.pod.DatabaseModule.connection;
// Use configuration
});
Doh's unified resolution approach provides advantages:
Developers learn one core resolution algorithm that works across all Doh systems.
Predictability comes from graph-driven sequencing and explicit prerequisites. Overrides occur according to context-specific rules (e.g., MOC melding types). Only when two candidates remain unordered by dependencies does the tie-breaker apply, making the finally applied rule win.
All systems support multiple inheritance/dependencies with conditional inclusion.
The unified model allows different systems to work together coherently.
// Base component
Pattern('Component', {
// Core functionality
});
// Feature components
Pattern('DraggableComponent', {
// Dragging functionality
});
Pattern('ThemeableComponent', {
// Theming functionality
});
// Composed component
Pattern('AdvancedComponent', {
inherits: {
Component: true,
DraggableComponent: true,
ThemeableComponent: true
},
// Additional functionality
});
# base.yaml
database:
driver: postgres
timeout: 30
# development.yaml
inherits:
- base.yaml
database:
host: localhost
debug: true
# production.yaml
inherits:
- base.yaml
database:
host: production-db.example.com
pool_size: 20
We found that inheritance and dependency systems can be unified. By applying the same core principles across different contexts—from dependency loading to object composition—Doh creates a consistent and flexible framework.
This unified approach enables patterns like dynamic composition, conditional inheritance, and feature-based customization throughout the framework.
For more detailed information on specific aspects: