This page shows the source for this entry, with WebCore formatting language tags and attributes highlighted.

Title

Narrowing types to avoid primitive obsession

Description

Recently, I saw that the following error had been fixed in a code review. <img src="{att_link}classic_primitive_obsession.png" href="{att_link}classic_primitive_obsession.png" align="none" caption="Classic primitive obsession error" scale="65%"> The error shown above is an example of a <a href="https://en.wikipedia.org/wiki/Design_smell">design smell</a> called <a href="https://enterprisecraftsmanship.com/posts/functional-c-primitive-obsession/">Primitive Obsession</a>. This is where code is "obsessed" with primitives, in that it uses a much "wider" type than is actually acceptable. Whereas C++ has a <c>typedef</c>, TypeScript and Delphi Pascal have a <c>type</c>, C# has ... nothing simple. The <a href="https://enterprisecraftsmanship.com/posts/functional-c-primitive-obsession/">linked article</a> describes a hand-coded version for making "narrower" types (e.g., <c>MeanLength</c> or <c>ShortFiber</c>). Our go-to generated-source guru <a href="https://andrewlock.net/">Andrew Lock</a> describes a solution that uses the <a href="https://andrewlock.net/updates-to-the-stronglytypedid-library/">StronglyTypedId</a> package, but also links to a series from 2020 by Thomas Levesque that <a href="https://thomaslevesque.com/2020/10/30/using-csharp-9-records-as-strongly-typed-ids/">uses records</a>. It looks like you can use something like <c>public record MeanLength(int Value);</c> to succinctly define a narrower type. While it's <i>nice</i> that C# autogenerates all the necessary machinery (equals, hashCode, etc.) for the record, it's also <i>unfortunate</i> that it's necessary, as we're usually just trying to disambiguate two <c>ints</c> without further validation or restriction. Also, I'm not recommending you leverage the type system to avoid primitive confusion in every code base! I'm just noting that the error that arose is so common that it not only has a name, but that there are well-defined solutions for avoiding that class of problems using the type system. Before you start messing with these types in a language like C#---where, as noted, you don't have a simple type-disambiguation mechanism---you need to have everyone in the team on board. Many programmers will consider them to be too heavy-handed (they suspect it affects performance somehow, and aren't willing to trade any potential and unproven performance drawback anywhere for increased type-safety). Those are usually the same programmers who write code with <i>a ton</i> of primitive obsession and <i>zero</i> automated tests, so take their critique for what it's worth.