Two cases showing imperfection of the const system

Andrei Alexandrescu SeeWebsiteForEmail at erdani.org
Thu Feb 16 15:14:52 PST 2012


On 2/16/12 3: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.

Hold them horses. I disagree. You're just saying it, but what's your basis?

> 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?

This boils down to: "You want to sort an array of T[], U[], or V[], 
where the three types are loosely-related, except U is a supertype of 
both T and V and the three have the same layout. What would be the 
signature of such a function?"

The answer is (to a reasonable approximation) simple:

sort(X)(X[] data) if (is(X : U) && X.sizeof == U.sizeof);

This has nothing to do with qualifiers. Qualified types are distinct, 
and obey the classic subtyping and layout rules known since the dawn of 
humankind: const is a supertype of mutable and immutable, and they all 
have the same layout. Complaining about that equates to complaining 
about subtyping.

> 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 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.

You'd do the same if you wanted to sort arrays of base and arrays of 
derived with the same routine.

> 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.

I don't know how to swim with a hand tied to my back, either. The 
correct approach is to integrate templates in the discussion and analyze 
_that_ context, not the artificial context that precludes templates. D 
is not Go.

> But as I said in the preface, you shouldn't need templates
> for such a simple task.

char and const char are different types. The embedded presupposition is 
that they are somewhat similar, the qualifier being some sort of 
attribute of the type. That's not the case.

> 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.

Agreed.

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

Associative arrays must be templates.

> 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.

Again, we must make templates a part of the setup and discuss what's 
going on.


Andrei


More information about the Digitalmars-d mailing list