Definitely, I know the basic differences between unsigned integers (uint
) and signed integers (int
).
I noticed that in .NET public classes, a property called Length
is always using signed integers.
Maybe this is because unsigned integers are not CLS compliant.
However, for example, in my static function:
public static double GetDistributionDispersion(int tokens, int[] positions)
The parameter tokens
and all elements in positions
cannot be negative. If it's negative, the final result is useless. So if I use int
both for tokens
and positions
, I have to check the values every time this function is called (and return non-sense values or throw exceptions if negative values found???), which is tedious.
OK, then we should use uint
for both parameters. This really makes sense to me.
I found, however, as in a lot of public APIs, they are almost always using int
. Does that mean inside their implementation, they always check the negativeness of each value (if it is supposed to be non-negative)?
So, in a word, what should I do?
I could provide two cases:
Should we use different schemes for these two cases?
Peter
P.S.: I did do a lot of research, and there is still no reason to convince me not to use uint
:-)
I see three options.
Use uint
. The framework doesn't because it's not CLS compliant. But do you have to be CLS compliant? (There are also some not-fun issues with arithmetic that crop up; it's not fun to cast all over the place. I tend to void uint
for this reason).
Use int
but use contracts:
Contract.Requires(tokens >= 0);
Contract.Requires(Contract.ForAll(positions, position => position >= 0));
Make it explicit it exactly what you require.
Create a custom type that encapsulates the requirement:
struct Foo {
public readonly int foo;
public Foo(int foo) {
Contract.Requires(foo >= 0);
this.foo = foo;
}
public static implicit operator int(Foo foo) {
return this.foo;
}
public static explicit operator Foo(int foo) {
return new Foo(foo);
}
}
Then:
public static double GetDistributionDispersion(Foo tokens, Foo[] positions) { }
Ah, nice. We don't have to worry about it in our method. If we're getting a Foo
, it's valid.
You have a reason for requiring non-negativity in your domain. It's modeling some concept. Might as well promote that concept to a bonafide object in your domain model and encapsulate all the concepts that come with it.