Home Doh Ref
Dohballs
  • 📁 doh_modules
    • 📦 dataforge
    • 📦 express
    • 📁 sso
    • 📁 user

Resolution Order

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 Universal Composition System

Core Principles

The resolution system handles multi-source composition through these capabilities:

  1. Multiple Source Handling: Any system can compose from multiple sources simultaneously—packages can depend on multiple other packages, patterns can inherit from multiple parent patterns, configurations can cascade from multiple sources
  2. Deterministic Ordering: Complex dependency graphs are flattened into predictable, linear sequences using explicit prerequisites and dependency relationships
  3. Conditional Composition: Sources can be included conditionally based on environment, runtime state, or other requirements

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 Resolution Process

The universal composition algorithm operates through four phases that transform multi-source relationships into predictable, linear sequences:

  1. Source Identification: Discover all composition sources from explicit declarations across the inheritance/dependency tree
  2. Recursive Expansion: Build the complete dependency graph, resolving sub-dependencies recursively to ensure nothing is missed
  3. Deterministic Flattening: Transform the multi-dimensional dependency graph into a linear sequence using explicit prerequisites and dependency relationships
  4. Conditional Evaluation: Apply environment-specific and runtime conditions to determine which sources from the flattened sequence actually participate

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.

Domain-Specific Implementations

While the core 4-phase algorithm remains consistent, each system implements it with specialized behaviors:

Patterns: Multi-Layered Resolution (Most Complex)

Pattern resolution applies the algorithm multiple times in sophisticated ways:

  1. Module Dependency Resolution: Determines which modules are needed to build the pattern AND its entire child structure
  2. Pattern Inheritance Resolution: Resolves the pattern's own inheritance chain using conditional logic (hard vs soft inheritance, nested conditions)
  3. Property Merging: Uses resolution order to determine how properties combine via MOC (Melded Object Composition) rules
  4. Method Stacking/Hooking: Applies resolution order to determine method execution chains and lifecycle hooks

Pattern resolution operates across multiple composition domains simultaneously.

Pods: Hierarchical Configuration

Pod resolution implements the algorithm for cascading deep merges:

  1. Multi-Inheritance: Supports inheriting from multiple pod files simultaneously
  2. Deep Merging: Objects merge recursively, arrays merge uniquely, primitives override
  3. Deterministic Removers: ~~key syntax for explicit removal follows resolution order
  4. Environment Awareness: Conditional inclusion based on runtime context

Permissions: Group Composition

Permission resolution enables group merging with composition logic:

  1. Group Inheritance: Multiple permission groups can be composed
  2. Access Merging: Permission sets combine according to resolution rules
  3. Removers: Like pods, supports ~~permission syntax for explicit denial
  4. Precedence: Resolution order determines which group settings take priority

Modules: Dependency Orchestration

Module resolution focuses on execution order and parameter injection:

  1. Load Order: Determines module execution sequence based on dependencies
  2. Parameter Resolution: Scoped parameter names resolved via resolution order through ancestor chain
  3. Conditional Loading: Environment-specific modules included based on evaluation phase
  4. Asynchronous Flow: Resolution order preserved even with async module execution

Universal System in Practice

The same composition approach applies across all Doh systems, demonstrating how a single, well-designed solution can handle diverse composition requirements.

1. Dependency Loading: Resource Management Through Resolution

The Load System demonstrates the resolution approach solving dependency orchestration—ensuring resources are available in the correct order across different environments and loading contexts.

Implementation Details

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']);

Key Features

  • Recursive Expansion: Dependencies of dependencies are automatically resolved
  • Circular Detection: The system identifies and prevents circular dependencies
  • Conditional Loading: Environment-specific dependencies are conditionally included
  • Asynchronous Flow Control: Supports both synchronous and asynchronous loading patterns

Resolution Order Example

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.

2. Configuration Cascading: Resolution Applied to Hierarchical Settings

The Pod system demonstrates the resolution approach solving configuration inheritance—ensuring that settings from multiple sources combine predictably to create coherent, hierarchical configuration systems.

Implementation Details

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
}

Key Features

  • Recursive Inheritance: Pod files can inherit from other pod files, which themselves inherit
  • Deep Merging: Configuration objects are deeply merged based on resolution order
  • Environment Awareness: Supports different configurations for different environments
  • Override Control: Later pod files override earlier ones in the inheritance chain

Resolution Order Example

# pod.yaml
inherits:
  - base_config.yaml
  - environment/development.yaml
  - feature/authentication.yaml

# Custom overrides
database:
  host: localhost
  port: 5432

Resolution order:

  1. base_config.yaml (and its inheritance chain)
  2. environment/development.yaml (and its inheritance chain)
  3. feature/authentication.yaml (and its inheritance chain)
  4. Local pod properties (overriding previous values)

3. Pattern System (Melded Object Composition)

The Pattern system provides the most multi-layered implementation of resolution order, applying the algorithm across multiple composition domains simultaneously.

Algorithm Implementation

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
}

Key Features

  • Hard vs. Soft Inheritance: Distinguishes between guaranteed and conditional inheritance
  • Inheritance Hardening: Converts soft dependencies to hard when conditions are met
  • Nested Conditions: Supports complex conditional inheritance rules
  • Method Melding: Determines how methods from different patterns are combined

Inheritance Types

  1. Hard Inheritance (true): Pattern will always be included

    inherits: { 
        BasePattern: true  // Always included
    }
    
  2. Soft Inheritance (false): Pattern will only be included if required elsewhere

    inherits: { 
        OptionalPattern: false  // Conditionally included
    }
    
  3. Conditional Inheritance (object): Pattern will be included based on complex conditions

    inherits: { 
        ConditionalPattern: {  // Included only if DepPattern is also included
            DepPattern: true
        }
    }
    

Resolution Order Example

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:

  1. object (implicit base)
  2. BaseComponent
  3. UIComponent
  4. DraggableComponent (included due to ResizableComponent)
  5. ResizableComponent
  6. AdvancedComponent
  7. SpecializedComponent

4. Module System (Load and Execution)

Modules combine dependency resolution with execution order management.

Algorithm Implementation

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']);

Key Features

  • Dependency-Based Loading: Module load order is determined by dependencies
  • Layered Parameter Resolution: Callback parameters are resolved by name via a deterministic scope tree (current module's producers → ancestors), enabling module callbacks to consume names that earlier modules produced without re-importing
  • Asynchronous Execution: Supports both sync and async module callbacks
  • Conditional Loading: Supports environment-specific module activation

Resolution Implications

The module resolution order affects:

  1. Code Execution Sequence: Which module code runs before others
  2. Shared Object Population: How shared objects are initialized and which layer provides them first
  3. Pattern Availability: When patterns become available for instantiation

Cross-System Integration

How these separate systems interact is what makes Doh's resolution system work:

Pattern Inheritance → Object Construction

const myComponent = New('SpecializedComponent', {
    // Properties
});

The pattern resolution order controls:

  • Which properties and methods the object inherits
  • How methods are melded together
  • The sequence of phase method execution

Module Dependencies → Pattern Availability

Doh.Module('UIModule', ['BaseComponents'], function() {
    // Can safely use patterns defined in BaseComponents
    Pattern('CustomButton', 'Button', {
        // Button is defined in BaseComponents
    });
});

Pod Inheritance → Module Configuration

# 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
});

Benefits of Unified Resolution

Doh's unified resolution approach provides advantages:

1. Consistent Mental Model

Developers learn one core resolution algorithm that works across all Doh systems.

2. Predictable Composition and Overrides

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.

3. Flexible Composition

All systems support multiple inheritance/dependencies with conditional inclusion.

4. Seamless Cross-System Integration

The unified model allows different systems to work together coherently.

Practical Applications

Building Extensible Component Libraries

// 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
});

Environment-Specific Configuration

# 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

Conclusion

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:

Last updated: 10/22/2025