Hmm - about manifest/enum

Christopher Wright dhasenan at gmail.com
Wed Jan 2 17:26:45 PST 2008


Janice Caron wrote:
> But whatever the syntax, I must conclude that it can't be done,
> without violating one or more of the principles of D, and that's what
> Walter (and I) are trying to explain here.

You pick over cases where this is clearly the case; those where it is 
not clear, you just say this and no more. You could at least provide a 
link to the relevant discussions in webnews. Otherwise, I have no reason 
to believe you and every reason to doubt.

>> If references are to be consistent, the
>> meaning of an int reference is that it acts like an int until you assign to
>> another int reference.  If you assign it to another int reference, then type
>> now references the same thing as the new int reference.  If you assign it to
>> another int, that is a compiler error (can't assign a non reference value to
>> a reference just like you can't assign a non pointer value to a pointer).
> 
> D doesn't have a reference-to-int type, only reference-to-class-data.

We do, actually: int*.

> This appears to be a new feature request.

Yup. Because it looks kludgy to use const(T)*, and it looks kludgy to 
use const(T), and so I'm betting const will be used as often in D as in C++.

>> One further thing.  If you could at least pledge to have a way to specify a
>> tail-const class reference before 2.0 is officially released, I would be
>> willing to accept that for now.
> 
> Walter cannot do that without sacrificing generic programming.

Well, the thing is, we already have a technique to get tailconst 
anything, and that's using a pointer. As far as I can tell, people just 
want a prettier syntax for using mutable pointers to const data, and an 
equivalent to const(Object)* that involves one pointer dereference 
instead of two to access the object. Pretty syntax isn't a minor thing, 
either.

Also, there's the problem, with pointers:
const(T)*[] array = init_array();
array.sort; // sorts according to pointer values -- eep!

This can mess with generic programming, too:
struct S { int i; }
void reset_first_element(T)(array[] array) {
    static if (is (T == class)) {
       array[0] = new T();
    } else {
       array[0] = T.init;
    }
}
const(S)*[] array = init_array();
reset_first_element(array);

(channeling Gunther Hermann)
I wanted *array[0] == S.init.
It gave me segmentation fault.


Then the 'right' way would be something like:
void reset_first_element(T)(array[] array) {
    static if (is (T == class)) {
       array[0] = new T();
    } else static if (is (T == const(U)*, U)) {
       static if (is (T == class)) {
          *array[0] = new U();
       } else {
          *array[0] = U.init;
       }
    } else {
       array[0] = T.init;
    }
}

And that doesn't distinguish between situations where I want a reference 
and I want an actual pointer.

Basically, references solve a bunch of problems with const and with 
generic programming. The previous example becomes:

void reset_first_element(T)(array[] array) {
    static if (is (T == class)) {
       array[0] = new T();
    } else static if (is (T == U&, U)) {
       array[0] = U.init;
    } else {
       array[0] = T.init;
    }
}

Or maybe, depending on what T&.init is, you could eliminate the second 
element.

C# did something clever: for any value type T, new T() returns T.init. 
This makes sense; for value type T, T.init is usually sensible, or at 
least a lot more useful than null. So you'd get:
void reset_first_element(T)(array[] array) {
    static if (is (T == U&, U)) {
       array[0] = new U();
    } else {
       array[0] = new T();
    }
}

Or even:
void reset_first_element(T)(array[] array) {
    array[0] = new T();
}

Whether it's desirable for D is another matter.



More information about the Digitalmars-d mailing list