@mlhaufe/object-algebra
v0.1.1
Published
An implementation of Object Algebras
Downloads
1
Maintainers
Readme
Object Algebra
Implementation of Object Algebras to enable Feature-Oriented Programming (FOP).
Installation
The latest version:
npm install @mlhaufe/object-algebra
A specific version:
npm install @mlhaufe/[email protected]
For direct use in a browser (no build step):
<script type="importmap">
{
"imports": {
"@mlhaufe/object-algebra": "https://unpkg.com/@mlhaufe/object-algebra/index.mjs",
}
}
</script>
<script type="module">
import {Merge} from '@mlhaufe/object-algebra';
console.log(typeof Merge); // 'function'
</script>
Usage
Declare the Algebra:
interface PointAlg<T> extends Algebra {
Point2(x: number, y: number): T
Point3(x: number, y: number, z: number): T
}
Define Data:
class PointData { }
class Point2 extends PointData {
constructor(readonly x: number, readonly y: number) { super() }
}
class Point3 extends PointData {
constructor(readonly x: number, readonly y: number, readonly z: number) { super() }
}
Define Factory for the data:
class PointDataFactory implements PointAlg<PointData> {
Point2(x: number, y: number) {
return new Point2(x, y)
}
Point3(x: number, y: number, z: number) {
return new Point3(x, y, z)
}
}
Define a couple traits:
interface IPrintable { print(): string }
class Printable implements PointAlg<IPrintable> {
Point2(x: number, y: number): IPrintable {
return {
print() { return `(${x}, ${y})` }
}
}
Point3(x: number, y: number, z: number): IPrintable {
return {
print() { return `(${x}, ${y}, ${z})` }
}
}
}
interface IAddable { add(other: PointData & IAddable): this }
class Addable implements PointAlg<IAddable & PointData> {
Point2(x: number, y: number): IAddable & Point2 {
const family = this
return {
add(other: Point2 & IAddable) { return family.Point2(x + other.x, y + other.y) }
} as any
}
Point3(x: number, y: number, z: number): IAddable & Point3 {
const family = this
return {
add(other: Point3 & IAddable) { return family.Point3(x + other.x, y + other.y, z + other.z) }
} as any
}
}
Compose the features into a single class:
import {Merge} from '@mlhaufe/object-algebra';
class PointFactory extends Merge(PointDataFactory, Printable, Addable) { }
// Alternatively:
// const PointFactory = Merge(PointDataFactory, Printable, Addable)
const { Point2, Point3 } = new PointFactory()
const p1 = Point2(1, 2)
const p2 = Point2(3, 4)
console.log(p1.print()) // (1, 2)
console.log(p2.print()) // (3, 4)
console.log(p1.add(p2).print()) // '(4, 6)'
More examples are available in the tests directory.
Future Work
TypeScript does not support Higher Kinded Types (#1213).
This means that the Merge
function will not track or merge the generics types of the composed classes.
This is generally a problem for container types like List
. You can see an example of in
ListAlg.test.mts directory.
TypeScript also does not support associated types (#17588) so an emulation of HKTs are also not possible via that feature (As described by Bertrand Meyer). Index types are close, but seem to be forgotten by the compiler.
There is another approach to HKTs that does leverage indexed types to some limited success, but it adds an additional syntactic burden to the user which I find unacceptable.