The x++ Chain of Command
in Blog
One of my favorite features of the x++ programming language is the ability to extend classes by creating a chain of command, also referred to as CoC
.
It allows multiple consumers to seamlessly augment existing code side-by-side with minimal work required from the owner.
This is especially valuable for software where customization is the norm and multiple independent parties want to customize the same code.
The result is a flexible extension model conforming to the open/closed principle.
Extending code
Given a class OrderSubmitService
as defined below, we want to customize the validation behavior when an order is submitted.
Inheritance is not an option, as the class is final. Furthermore, this approach requires that the class can be substituted at its call site, which is often not possible.
// file: "OrderSubmitService.xpp"
public final class OrderSubmitService // final class, no inheritance
{
protected SimpleOrder simpleOrder;
public void submitOrder()
{
if (this.validateOrder())
{
simpleOrder.submit();
}
}
protected boolean validateOrder()
{
return simpleOrder.Amount > 0; // we want to customize this
}
}
Ideally, we would like to just add our custom logic to the validateOrder
method.
Next
In order to create a chain of command, we create a new class with the _Extension
suffix and add a reference to the target class in the ExtensionOf
attribute.
Then we are free to declare any public or protected methods from the target class and define custom behavior.
In the below example we add another validation step to the existing one.
// file: "OrderSubmitService_Extension.xpp"
[ExtensionOf(classStr(OrderSubmitService))]
public final class OrderSubmitService_Extension
{
protected boolean validateOrder()
{
boolean isAvailable = this.simpleOrder.IsAvailable; // access to protected members
return next validateOrder() && isAvailable; // calling next is mandatory
}
}
Calling next invokes the next extension in the chain, until it reaches the base implementation.
In this way, independent parties can add more layers of code on top of the core, which can be locked down to prevent unintended side effects.
Looking at the code, this seems oddly familiar.
Parallels
There are no other languages with CoC support, AFAIK, but one parallel came to mind.
We can achieve similar results with @Around
advice in AOP as shown in the Kotlin Spring code below.
// file: "OrderSubmitServiceExtension.kt"
@Aspect
@Component
class OrderSubmitServiceExtension {
@Around("execution(* OrderSubmitService.validateOrder(..)) && target(orderSubmitService)")
fun validateOrder(next: ProceedingJoinPoint, orderSubmitService: OrderSubmitService): Boolean {
val isAvailable = orderSubmitService.simpleOrder.IsAvailable
return next.proceed() && isAvailable as Boolean
}
}
There are some major differences and changes needed to make this work, like not being able to access protected members, but otherwise it is really cool to observe the similarities here.
Calling next
in x++ is required, but we can ignore the result in both. Both provide access to the target class.
Whereas AOP is commonly leveraged to address cross-cutting concerns, CoC addresses the cross-cutting concern of code extensibility in x++.
The extension model of x++ is of course much more than CoC. For example, you can also add state to classes via extensions. But I have to say, I really came to appreciate the power of the Chain of Command in creating elegant, extensible solutions with minimal boilerplate.