Two cases showing imperfection of the const system
Timon Gehr
timon.gehr at gmx.ch
Thu Feb 16 14:42:17 PST 2012
On 02/16/2012 10:48 PM, SiegeLord wrote:
> Firstly, let me preface this... if you use templates to get around the
> const system's imperfections, you are admitting that the const system is
> broken. Now, on with the program.
>
> My unique experience in using D2 without Phobos lead me to encounter two
> cases that show how the D2 const system is just a pain in the behind for
> some really reasonable tasks.
>
> First case:
>
> You want to sort an array of strings using a function. Strings can be
> all of these types: char[], const(char)[] and immutable(char)[]. What
> would be the signature of such a function?
>
> It can't be sort(const(char)[][]) because it's unsafe to case char[][]
> and immutable(char)[][] to that argument type (see
> http://d.puremagic.com/issues/show_bug.cgi?id=4251 ).
> It can't be sort(const(char[])[]) because you can't actually sort that!
>
The correct signature is
void sort(inout(char)[][]);
This is currently illegal, see:
http://d.puremagic.com/issues/show_bug.cgi?id=7105
> The only good way I found is to use a cast inside the function with the
> second signature. Obviously I'm glad there's a workabout, but surely a
> cast isn't a good thing.
>
A type-safe workaround is to use the signature
inout(void) sort(inout(char)[][]);
> Second case:
>
> inout was meant to solve issues with functions that return slices of
> inputs. What about a class that is dedicated to the same functionality?
>
> E.g. this works fine:
>
> inout(char)[] half(inout(char)[]);
>
> But what about this:
>
> struct Slicer
> {
> char[] a;
> char[] half();
> }
>
> Note that the type of the input (the member 'a') must be the same as the
> output of the half method. I don't know how to accomplish this without
> templates. But as I said in the preface, you shouldn't need templates
> for such a simple task. Note that doing this isn't satisfactory:
>
> struct Slicer
> {
> char[] a;
> inout(char)[] half() inout;
> }
>
> because there may be other members inside that struct that may need to
> remain mutable.
>
For this example, there is no problem. But I see what you mean. Seems
like it would require some kind of parametric polymorphism. Ideally we'd
get Scala-like Generics with Java Wildcards ;)
struct Slicer[+T <: const(char)[]]{ // not a template!
T a;
int[] someOtherMember;
inout(T) half() inout;
}
void main(){
Slicer![char] sl1;
sl1.a = "string".dup;
char[] arr1 = sl1.half();
Slicer![immutable(char)] sl2;
sl2.a = "string";
string arr2 = sl2.half();
Slicer![const(char)] sl3;
sl3.a = "string".dup;
sl3.a = "string";
const(char)[] arr3 = sl3.half();
sl3 = sl1;
sl3 = sl2;
}
> This is very relevant, incidentally, for the planned library
> implementation of associative arrays. How would this be implemented when
> an associative array is a struct?
>
> inout(char)[] test(inout(char)[])
> {
> inout(char)[][int] a;
> }
>
> It doesn't even compile now (in dmd 2.058).
>
It does. The problem is that your function is missing a return
statement. Anyway, when an associative array is a template struct then
there is basically no non-magical way to implement what you want.
However, if we introduce generics, the solution would look similar to
this sketch:
struct AssocArray(S, T)[K <: const(S), V <: const(T)]{
V lookup(K);
...
}
'test' would be rewritten by the compiler as:
inout(char)[] test(inout(char)[]) {
AssocArray!(int,char[])![int,inout(char)[]] a;
// ...
}
> I don't have any solutions to these problems, incidentally... I think
> they are complex, but definitely worthy of having a reasonable solution
> that doesn't involve needless (in this case) templates.
>
> -SiegeLord
The first problem is trivial, solving the second one in a type safe way
would require adding parametric polymorphism to D. (Which I'd love to have!)
More information about the Digitalmars-d
mailing list