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!)



Reply via email to