Hi Hal, good point, thanks for calling me on this.
Hmmm, how to start. I think the purpose of giving a field a type is to specify what values it may take. So if a field can take integer values 1, 3, and 7, it would be best to declare that field using this information like
rather than just
int f; // should only take 1, 3, 7 values
This way, the compiler or the runtime system could check value assignments for correctness. The purpose of code in the owning object then becomes only to maintain constraints between fields, not within a single field.
Once you start doing this, you'll recognize that most of what you did before was underspecifying fields. I once contributed to a large banking application
BGKetal97 where we had only about 50 fundamental value types but a huge number of derived value types. For example, we had a value type (class) for legacy system code communication, but then would derive literally hundreds of value types, one for each possible command. (But you only start doing this once it is easy, or you have strong and opinionated QA :-)
So, the observation is that there is a small set of interesting value types, and a much larger set of not-specifically-spectacular value types. The interesting value types tend to be more
Value Type Constructors than plain value types, like the concept of enum is a value type constructor.
I should go back to that particular project and get some data, it still represents the biggest example experience I have in this space; I may have gone overboard with "majority". Maybe it is more like 50% to 50%. But I think it is not that value types are just a small minority of domain concepts.