Universal domain types
mmapped.blog
mmapped.blog
[0]: https://medium.com/the-sixt-india-blog/primitive-obsession-c...
I don't mean to be pedantic. But it's quite exhausting trying to parse the meaning out of "primitive obsession is a code smell". It took me a while to figure out whether the author considered "primitive obsession" to be a good thing or a bad thing, not least because the they provided an example but not a definition.
https://deque.blog/2017/08/17/a-study-of-4-money-class-desig...
First, you can have a type-checker check the currency; that doesn't have to be a runtime error:
Money<Usd> m = …;
There will, of course, be instances where you must handle currency dynamically."MoneyExpr" is a bit more complicated; I find most people usually implement "MoneyBag" intuitively first, so it's odd they left that for third? So, the article gets there, and we "fix" the problems, but it feels roundabout.
The criticism of MoneyBag is bizarre:
> Compared to the Martin Fowler’s design, it remains heavier. It consumes more memory and more CPU
This is apples to oranges? Fowler's design is a Money type; MoneyBag is a different thing; of course it consumes more memory. A Vec<int> consumes more memory than an int, too?
Perhaps the article author isn't comfortable with that Money merely isn't closed over addition. But if you accept that Money isn't closed over addition, then naturally there must be another type in the type system.
With dependent types, checking for currency validity may be handled at compile-time. (This is touched upon in the post linked in the comment you replied to.)
For the case of conversion between currencies of monetary amounts:
https://github.com/anderslundstedt/type-experiments#type-saf...
> I find most people usually implement "MoneyBag" intuitively first, so it's odd they left that for third?
I have not found that at all.
Programming by specifying algebraic properties is very easy and natural, but in most languages it's a pain to encode in the type system.
1. Don't restrict yourself to "common" types when you're thinking this way -- all of domain modeling can be approached this way. Working on a Pizza Ordering app? Think about the properties of various operations in your domain and how they are related to mathematical structures. Are they commutative, well-orderable, equatable, multiplicative, scalar, groups/rings/fields, monoids? Are there changes you can make that would allow your operations to have desirable properties? This stuff genuinely does pay off down the road when you want to expand your ideas or re-use your code on something else.
But be careful: not all useful mathematical structures have names or show up in textbooks! The goal is not to map your domain to things that mathematicians have named, it's just to understand it at this level (and get your code to understand it at this level too). If you find yourself arguing over whether it's actually a vector space, a tensor space, or an affine space, then stop worrying about external definitions and re-focus on the properties of your domain. Arguments about how your domain works are good; arguments about exactly what other mathematicians have written are bad.
2. This post is focused on getting the compiler to understand these concepts, but there's still a lot of value in explicitly modeling them in code even if it's "runtime checked" instead of compile-time checked. Many of these techniques end up requiring higher-kinded types to really get the compiler on board, which unfortunately most languages today don't support. But that doesn't mean you should change the abstraction, it just means you get a lower (or later) level of checking.
> 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.
I don't understand what this is trying to say and this "mathematical model" of sets doesn't seem to be applied further on. In math, objects are usually always assumed to have a notion of equality, so I don't see how that alone implies a set. A mathematical abstraction that matches the `Eq` trait would be a setoid.
The `LocusLike` trait is a lot like a metric space with a total order. I wonder if it can be implemented by things that are not basically numbers under the hood (not that it needs to, just curious)?
> Unlike design patterns, the universal domain types are based on mathematical abstractions and can be specified precisely.
I feel like this is over-selling it a bit. I think the ideas are great but, at least as presented here, I don't think they are rigorous enough to deserve the label "mathematical abstractions".
I think what is meant by it is that we have a set without additional structure. Other structures like vector spaces, groups, fields, etc. are (at least in mainstream maths) also sets, but they're equipped with structure - operations and axioms that govern how these operations work. But if you have just a set, you can't assume anything about the internal structure of what's in that set.
1. https://github.com/manifold-systems/manifold/tree/master/man...
...Why don't we just import he rest of algebra here :)