0

This question already has an answer here:

Often times in programming, we need to represent some value which can easily be represented using a simple primitive type.

For example, in a game we might need to represent the velocity of a moving object. This could easily be represented with a double value. This object might also have a value of mass; this can also be represented with a double.

Some would argue that we should have a Speed type and a Mass type for each of these, instead of the general-purpose double type. The argument for that is that this way we take advantage of 'strong-typing'; the compiler doesn't let us pass a speed for a mass or a mass for a speed and make mistakes like those.

This argument makes sense. However, I can't help but thinking that this would be an overkill.

So what would you use? A simple double (following KISS and keeping everything as simple as possible) or a type made for a specific purpose?

marked as duplicate by Telastyn, gnat, MSalters, Kilian Foth, durron597 Jun 24 '15 at 14:01

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • @CodesInChaos Who said anything about performance? – Aviv Cohn Jun 20 '15 at 17:47
  • I misread the word "Speed" in the title. – CodesInChaos Jun 20 '15 at 17:48
  • Recommended reading: typedef. – user22815 Jun 20 '15 at 18:19
  • typedef does not provide any safety guarantees. It is only useful as documentation. – Rufflewind Jun 20 '15 at 19:24
3

I would say yes if that type has a meaning more than just the simple value. In your example, Speed and Mass might be represented by a double, but they have different meanings, and they have different calculations that can be done on them.

I can tell you from personal experience that doing this (it's called micro domain btw), has made my code much more readable and saved me lots of times from passing the wrong variable by mistake.

2

It depends on the language as well as how much effort you are willing to invest for increased correctness. There is a delicate balance between "concise code" and "rigorous code", but the location of this will vary from language to language and also depending on personal taste and circumstances. For example, if you're just prototyping, it may not be worthwhile at all.

In some cases, the benefit is worth the extra cost – the most commonly cited example are string wrappers that allow unsafe input strings to be distinguished from strings written by the programmer, thus reducing the risk of an accidental injection attack when these strings are concatenated carelessly.

One can do the same with quantities too. Some languages even have libraries that allow you to deal with units in a general way, if the type system is powerful enough to support such a feature.

Performance-wise, many languages are capable optimizing out trivial wrapper data types, so it may not have any performance impact at all, except perhaps reducing compilation speed slightly.

1

F# solves this problem nicely with measures:

[<Measure>] type cm
[<Measure>] type ml = cm^3

For other languages, its a tradeoff (like everything). Encapsulating primitives may have an impact on performance and space, but has benefits in type safety. You may confuse younger developers (and possibly older ones too), so there are potential readability issues, as well as productivity losses if you don't implement the thing correctly, or if the language doesn't allow you to fully implement something like this. For instance, would you be able to implicitly cast to your new encapsulated type? MyNewType i = 2; How does equality work? i == 2. etc.

  • F# got the idea from C++. IIRC, Fermi Labs developed the SI units lib around 2002 or so. No performance impact of course, C++ has no abstraction penalty for such simple wrappers. And it correcly resolves that Length L; L==2; is invalid. 2 is a dimensionless number (meters^0), length is not (meters^1). That's a straightforward type error. Instead, use L==2_m (user-defined literals) – MSalters Jun 23 '15 at 14:11
0

You could probably figure this out by checking over the use cases of a quick sample. I'd say this makes sense if you can easily summarize and implement each of the use cases of, say, a numerical type. The entire point of a type system is to help you realize when you're working with the wrong type, and that can catch lots of issues before they happen. It could also make it easier to change the arguments of a method if you decide to, say, reorder "position / velocity" so it reads better; everything that doesn't match will throw a compile error.

But if you have a type that is always added to, subtracted to, divided, and all kinds of different math operations in various service classes, and doing so without taking out the primitive type is annoying, then that may indicate there's a better design for it.

Since all primitives have something they're being used for (self-obvious), it's possible to mis-apply that principle; it would of course be overkill to do things like wrap an "enabled:Boolean" property as "enabled:EnabledState" unless you had a very good reason (cvars, in a video game, might be a good example but I have not implemented such a system before)

0

I'm in favor of the micro domain types as @Miki describes them. I've done both and the code that has the custom types is easier to maintain than the code using primitive types, especially in large projects. Making changes and/or finding uses is easier, and the compiler can help catch errors, too. What's not to like? Of course, C# has structs which makes using a wrapper practically free, for example, an array of structs is very efficient compared to an array of objects, and also, the CLR does particularly well with 1-element structs. With Java, I think you pay a price for the wrapper (have they added value types yet?).

0

If the value is just that - the value, stick to using it as a field on another object. Mass and Speed are 2 different things indeed, but the fact that I created a separate type for each doesn't really mean I wouldn't mix the two up when I create new instances of those objects - in other words - NO, simple types are simple for a reason and you shouldn't complicate your code with new type for each simple value, because you could layer after layer trying to protect the future developer from mistakes, but you can only do so much.

Not the answer you're looking for? Browse other questions tagged or ask your own question.