Should 0 total duration be a valid state for a timer?
It's a sentinel value that might take care of some edge cases, but then have to guard against division by 0 when calculating progress ratio (elapsed/total). It's the only sensible default initialization value, but it also doesn't really makes sense conceptually - it's done/triggered before it's even started.
@freemo You can add a specific language context you are most familiar with. I'm curious about any perspective, even if it's specific.
I wield the c++ chrono library and my ambition is to forge the timer to rule them all and in the darkness bind them *evil laugh*. I don't want people writing their own timers, what is this frivolity?!
I'm not sure what creation of timers have to do with the zero guard. Timer being just a number or two, creation cost is negligible, and the division does not occur during creation, but when checking the progress ratio, which can happen quite often. Say, in context of animation that can be every screen refresh, and there can be a lot of timers involved, as their are used for "inbetweening" (go from A to B in X time). In a more general sense though, the ratio calculation is just a division, usually one instruction, and adding the guard can add a significant relative overhead (I don't know 30-100% maybe). It might not matter, but I want to cover the cases where it matters as well.
The default initialization is usually considered a good thing if it's meaningful, since it's what the basic value types do. As in "here is my super simple type, if you can handle an int, you can hand it as well". Especially if you allow initialization to any value and the value type has a common sense default, preventing default initialization is kind of wonky. There is very little difference between
Type(),
and
Type(0),
except that the latter requires the literal 0, which in context of time durations is a bit problematic, since it needs units. Even dealing with arithmetic types in generic code people will often prefer the default initialization to a literal 0, since the type in question might not want to be in general constructable from a single integer (2D vector that requires 2 integers, but also defaults to natural [0,0]) or the value corresponding to integer zero might not be the best default (additive identity for floats is -0).
A special "0 timer" type can't really solve the performance issue for a value not knows at compile time, since it would require some sort of dynamic polymorphism, that would likely generate a worse check and a worse branch that the simple guard would. For values knows at compile time, the compiler will like optimize the guard away, so it's really all about the runtime requirements.