Inspired by: https://mmapped.blog/posts/25-domain-types.html
interface Amount <SELF, SCALAR> Source #
A typical use of domain types is representing quantities, such as the amount of money in USD in a bank account, or the file-size in bytes. Being able to compare, add, and subtract amounts is essential.
Generally, we cannot multiply or divide two compatible amounts and expect to get the amount of the same type back.
Unless we’re modeling mathematical entities, such as probabilities or points on an elliptic curve.. Multiplying two dollars by two dollars gives four squared dollars. I don’t know about you, but I’m yet to find a practical use for squared dollars.
Multiplying amounts by a dimensionless number, however, is meaningful. There is nothing wrong with a banking app increasing a dollar amount by ten percent or a disk utility dividing the total number of allocated bytes by the file count.
The appropriate mathematical abstraction for amounts is vector spaces. Vector space is a set with additional operations defined on the elements of this set: addition, subtraction, and scalar multiplication, such that behaviors of these operations satisfy a few natural axioms.
This is the same as VectorSpace
but with ordering
type | SELF | Type implementing this interface |
type | SCALAR | Scalar units |
interface DomainType <SELF> Source #
Fundamental base-trait for implementing domain-types. This is the basis for Identifier
, Locus
, VectorSpace
,
and Quantity
. It allows the derived types to be safely instantiated from simpler values, like int
, float
, etc.
And, to be converted back from the domain-type to the simpler representation.
type | SELF | Type implementing this interface |
interface DomainType <SELF, REPR> Source #
Fundamental base-trait for implementing domain-types. This is the basis for Identifier
, Locus
, VectorSpace
,
and Quantity
. It allows the derived types to be safely instantiated from simpler values, like int
, float
, etc.
And, to be converted back from the domain-type to the simpler representation.
type | SELF | Type implementing this interface |
type | REPR | Underlying representation |
method Fin<SELF> From (REPR repr) Source #
Creates a domain value from its representation value
returns | Either an |
method SELF FromUnsafe (REPR repr) Source #
Creates a domain value from its representation value
returns | Either throws an exception or returns a validly constructed |
interface Identifier <SELF> Source #
One of the most common uses of domain types is a transparent handle for an entity or an asset in the real world, such as a customer identifier in an online store or an employee number in a payroll application. I call these types identifiers.
Identifiers have no structure, i.e., we don’t care about their internal representation. The only fundamental requirement is the ability to compare values of those types for equality. This lack of structure suggests an appropriate mathematical model for such types: a set, a collection of distinct objects.
type | SELF | Type implementing this interface |
interface Locus <SELF, DISTANCE, DISTANCE_SCALAR> Source #
Working with space-like structures, such as time and space, poses an interesting challenge. Spaces have two types of values: absolute positions and relative distances.
Positions refer to points in space, such as timestamps or geographical coordinates. Distances represent a difference between two such points.
Some natural languages acknowledge the distinction and offer different words for these concepts, such as o’clock vs. hours.
While distances behave the same way as Amount
, positions are trickier. We can compare, order, and subtract them to
compute the distance between two points. For example, subtracting 5 am on Friday from 3 am on Saturday gives us
twenty-two hours. Adding or multiplying these dates makes no sense, however. This semantic demands a new class of
types, loci (plural of locus).
We can view each position as a distance from a fixed origin point. Changing the origin or the distance type calls for a new locus type.
type | SELF | Type implementing this interface |
type | DISTANCE | Additive units |
type | DISTANCE_SCALAR | Distance scalar units |
interface VectorSpace <SELF, SCALAR> Source #
A typical use of domain types is representing quantities, such as the amount of money in USD in a bank account, or the file-size in bytes. Being able to compare, add, and subtract amounts is essential.
Generally, we cannot multiply or divide two compatible amounts and expect to get the amount of the same type back.
Unless we’re modeling mathematical entities, such as probabilities or points on an elliptic curve.. Multiplying two dollars by two dollars gives four squared dollars. I don’t know about you, but I’m yet to find a practical use for squared dollars.
Multiplying amounts by a dimensionless number, however, is meaningful. There is nothing wrong with a banking app increasing a dollar amount by ten percent or a disk utility dividing the total number of allocated bytes by the file count.
The appropriate mathematical abstraction for amounts is vector spaces. Vector space is a set with additional operations defined on the elements of this set: addition, subtraction, and scalar multiplication, such that behaviors of these operations satisfy a few natural axioms.
type | SELF | Type implementing this interface |
type | SCALAR | Scalar units |