Troubles with user defined subtypes
bearophile
bearophileHUGS at lycos.com
Mon Dec 17 14:34:51 PST 2012
Regarding the recent discussions on SafeInts and HalfFloats, I
find some difficulties in using user-defined sub-range of a type.
Let's say I want to define a new type as subset of all the chars,
that contains only the digits.
This is a very common need in my programs, I often want integral
values that are allowed to be only a subrange (or subset, if they
are sparse) of a built-in integral type.
(In Ada language there is syntax and semantics in the type system
to make this easy, safe and nice).
Here I have shown some general problems associated with the
creation and use of user-defined subtypes:
http://forum.dlang.org/thread/jhkbsghxjmdrxoxaevzm@forum.dlang.org#post-jhkbsghxjmdrxoxaevzm:40forum.dlang.org
This program shows two problems that make subtyping much less
handy/useful for me in D:
// Start program -------------------------------
struct Digit {
immutable char d;
this(in char d_) pure nothrow
in { assert(d_ >= '0' && d_ <= '9'); }
body { this.d = d_; }
alias d this;
}
U[] _validator(U, T)(in T items) pure nothrow {
typeof(return) result;
foreach (immutable d; items)
result ~= U(d);
return result;
}
template Digits(string s) {
enum Digits = _validator!Digit(s);
}
void main() {
import std.string: countchars;
immutable d1 = "12341234";
immutable n1 = countchars(d1, "23");
assert(n1 == 4);
// No array contravariance (through the Digit pre-condition):
Digit[] d2 = d1; // error.
Digit[] d3 = Digits!d1; // OK
// No array covariance, countchars requires a
// immutable(char)[] and refused a Digits[]:
immutable n2 = countchars(d3, "23"); // error
immutable n3 = countchars(d3, Digits!"23"); // error
}
// End program -------------------------------
The first problem is with array literals (here the array literals
are strings, but a normal dynamic array of chars is a similar use
case). If I define a subtype, like Digits, then I'd like a nice
ways to write them in an array/associative array literal. Such
literals should be compact, readable and yet they should be safe,
this means if in a string meant to become a Digits[] I put a "x",
the compiler should give me a compile-time error instead of a
run-time error.
To solve that contravariance+validation problem here I've used a
template and a compile-time function helper. It's not a too much
bad solution, but maybe there are ways to improve the situation.
The other problem is that a Digit[] despite being meant as a
subtype of char[], doesn't have covariance, so
std.string.countchars() doesn't accept a Digit[]. This makes such
subtyping much less useful.
A built-in annotation like this doesn't solve the problem:
@subtype alias d this;
Maybe a built-in annotation this this is enough, I don't know:
@subtype(char) struct Digit { ... }
Bye,
bearophile
More information about the Digitalmars-d
mailing list