Short list with things to finish for D2

dsimcha dsimcha at yahoo.com
Thu Nov 19 15:15:49 PST 2009


== Quote from Andrei Alexandrescu (SeeWebsiteForEmail at erdani.org)'s article
> > 2.  After thinking about this some more, the big issue I see is ref opIndex.  We
> > can either:
> >     a.  Disallow it for both UniqueArray and ArrayBuilder.
> >     b.  Allow it for both UniqueArray and ArrayBuilder and accept
> >         that a sufficiently dumb programmer can invalidate the
> >         guarantees of UniqueArray by taking the address of one of the
> >         elements and saving it somewhere.  Probably a bad idea, since
> >         assumeUnique() already works for the careful programmer, and
> >         UniqueArray is supposed to provide ironclad guarantees.
> >     c.  Don't define opIndex in the abstract base class at all, thus
> >         making Array almost useless as an abstract base class.
> Welcome to my demons :o).
> One possibility that I thought of for a long time would be to disallow
> taking the address of a ref. That reduces the scope of the problem but
> doesn't eliminate it:
> void main() {
>      auto a = new UniqueArray(10);
>      fun(a[0], a);
> }
> void fun(ref int a, UniqueArray b)
> {
>     auto imm = b.toImmutable();
>     // here a is a mutable alias into an immutable array!!!
> }
> So that doesn't work, but I thought I'd mention it :o).
> Another possibility is to expose opIndex to return by value and also
> opIndexAssign that sets the value. That would be a no-no in C++ because
> copying is arbitrarily expensive, but I have a feeling that in D it is
> sensible to consider and foster that all objects should be defined to be
> cheap to copy (e.g. refcounting, COW etc.) If we go by the notion that
> in D we can always assume copy costs are reasonable, this last
> possibility would work. With the newfangled operators, it would even
> work beautifully because you can do all sorts of things like a[1] += 4
> without ever exposing a ref to the user.
> Andrei

Eureka!  This is one of those corner cases where non-virtual, non-final class
member functions are tremendously useful.  Fortunately, we can simulate them my
making opIndex a template.

abstract class ArrayBase(T) {
    T* ptr;

    T opIndex(I : size_t)(I index) {
        return ptr[index];
    }
}

class ArrayBuilder(T) : ArrayBase!(T) {
    ref T opIndex(I : size_t)(I index) {
        return ptr[index];
    }
}

void main() {
    auto ab = new ArrayBuilder!(float);
    auto num = ab[0];  // Yes, this segfaults, but we only care
                       // that it compiles.
}


If the compile time type is an ArrayBase or any subtype of ArrayBase that doesn't
override opIndex, then we get value return.  If it's an ArrayBuilder, we get ref
return.  This happens regardless of what the runtime type is.  Precisely what we
wanted.



More information about the Digitalmars-d mailing list