IonIon
Packages
  • next
  • current
Changelog
GitHub
Packages
  • next
  • current
Changelog
GitHub
  • Version 0.x

    • Release Notes
    • Upgrade Guide
    • Contribution Guide
    • Security Policy
    • Code of Conduct
    • Origin
  • Packages

    • Introduction
    • Container

      • Introduction
      • Prerequisites
      • How to install
      • Container Instance
      • Bindings
      • Dependencies
      • Resolving
      • Contextual Bindings
    • Contracts

      • Introduction
      • How to install
    • Support

      • Introduction
      • How to install
      • Arrays

        • About Arrays
        • Includes All
        • Includes Any
        • Is Array Like
        • Is Concat Spreadable
        • Is Safe Array Like
        • Is Typed Array
        • Merge
      • Concerns

        • About Concerns
        • Prerequisites
        • Concern Class
        • Using Concerns
        • Aliases
        • Conflict Resolution
        • Booting
        • Hooks
        • Edge Cases
        • JSDoc
      • Exceptions

        • About Exceptions
        • Configure Custom Error
        • Configure Stack Trace
        • Get Error Message
        • Custom Errors
      • Facades

        • About Facades
      • Meta

        • About Meta
        • Prerequisites
        • Supported Elements
        • Set & Get
        • Inheritance
        • Outside Changes
        • TC39 Proposal
        • Target Meta
      • Mixins

        • About Mixins
        • New Mixin
        • Apply Mixins
        • Instanceof
        • Inheritance
        • Onward
      • Object

        • About Objects
        • Forget
        • Forget All
        • Get
        • Has
        • Has All
        • Has Any
        • Has Unique ID
        • Is Cloneable
        • Is Populatable
        • Isset
        • Merge
        • Populate
        • Set
        • Unique ID
      • Reflections

        • About reflections
        • Assert Has Prototype Prop.
        • Class Looks Like
        • Class Own Keys
        • Get All Parents Of Class
        • Get Class Prop. Descriptor
        • Get Class Prop. Descriptors
        • Get Constructor Name
        • Get Name Or Desc. Tag
        • Get Parent Of Class
        • Has All Methods
        • Has Method
        • Has Prototype Property
        • Is Callable
        • Is Class Constructor
        • Is Class Method Reference
        • Is Constructor
        • Is Key Safe
        • Is Key Unsafe
        • Is Method
        • Is Subclass
        • Is Subclass Or Looks Like
        • Is WeakKind
      • Misc

        • About Misc.
        • Desc. Tag
        • Empty
        • Is Key
        • Is Primitive
        • Is Property Key
        • Isset
        • Merge Keys
        • To Weak Ref.
      • Callback Wrapper
    • Vuepress Utils

      • Introduction
      • How to install
      • Navigation

        • Archive
      • Plugins

        • Last Updated
      • Components

        • Version Disclaimer
    • XYZ (test package)

Edge Cases

  • Getter & Setter declared in different concerns
  • Inheritance vs. Concern members
  • Concerns using other concerns

Getter & Setter declared in different concerns

It is not possible to define a property's getter and setter methods in separate concerns, and thereafter use them in a target class. Despite serving different purposes, the getter and setter share the same property name and are therefore treated as being one and the same property key. The following example will therefore always lead to an AliasConflictError being thrown.

import { AbstractConcern, use } from "@aedart/support/concerns";

class A extends AbstractConcern {
    get title() { /* ...not shown.. */ }
}

class B extends AbstractConcern {
    set title(value) { /* ...not shown.. */ }
}

@use(
    A,
    B // AliasConflictError - "title" property from A!
)
class Person {}

You can resolve the above shown issue via a custom alias. But, it is advisable to design your concerns such that the offer appropriate getter and setter methods for a property, in one and the same concern - if you intend for such a property to be readable and writable.

Inheritance vs. Concern members

The concerns mechanism will never overwrite existing methods or properties inside a target class - not even when those methods or properties are inherited from a parent class.

import { AbstractConcern, use } from "@aedart/support/concerns";

class Connection extends AbstractConcern {
    driver() {
        return 'special';
    }
}

class Api {
    driver() {
        return 'default';
    }
}

@user(Connection) // driver() is NOT aliased - method inherited from Api class!
class SailBoat extends Api {}

const instance = new SailBoat();
instance.driver(); // default

The only way to resolve the above shown issue, is by making use of a custom alias and manually overwrite the inherited method. E.g.

import { AbstractConcern, use } from "@aedart/support/concerns";

class Connection extends AbstractConcern {
    driver() {
        return 'special';
    }
}

class Api {
    driver() {
        return 'default';
    }
}

@user(
    [Connection, {
        'driver': 'specialDriver' // alias "driver" as "specialDriver"
    }]
)
class SailBoat extends Api {
    
    // Overwrite inherited method
    driver() {
        // Invoke the "specialDriver"... 
        return this.specialDriver();
    }
}

const instance = new SailBoat();
instance.driver(); // special

Concerns using other concerns

A concern can use other concerns classes. However, depending on your complexity, doing so may impact performance. Consider the following example:

import { AbstractConcern, use } from "@aedart/support/concerns";

class Ping extends AbstractConcern {
    ping() {
        return 'ping';
    }
}

@use(Ping)
class Pong extends AbstractConcern {
    pong() {
        return 'pong';
    }
}

@use(Pong)
class Game {}

const instance = new Game();

instance.ping(); // ping
instance.pong(); // pong

In the above shown example, whenever the ping() method is invoked, the call stack will be similar to the following:

Game (instance).ping() -> Pong (instance).ping() -> Ping (instance).ping()

("->" represents concerns container instance)

In some isolated cases, this might be acceptable for you. Nevertheless, if your application makes heavy use of concerns using other concerns, then your application's overall performance could suffer. You should consider merging multiple concern classes into a single class, if it is reasonable and possible. Alternatively, you can also consider extending existing concern classes. For instance:

import { AbstractConcern, use } from "@aedart/support/concerns";

class Ping extends AbstractConcern {
    ping() {
        return 'ping';
    }
}

// Extend Ping concern...
class Pong extends Ping {
    pong() {
        return 'pong';
    }
}

@use(Pong)
class Game {}

const instance = new Game();

instance.ping(); // ping
instance.pong(); // pong

Now, whenever the ping() method is invoked, the call stack is slightly reduced:

Game (instance).ping() -> Pong (instance).ping()

("->" represents concerns container instance)
Edit page
Last Updated:
Contributors: alin
Prev
Hooks
Next
JSDoc