On Mon, 8 Nov 2010 17:08:32 -0800
Jonathan M Davis <jmdavisp...@gmx.com> wrote:

> As Jesse says, they _are_ passed by reference. The struct itself _is_ the 
> reference. 

(Well, that is a sensible redefinition of "reference"; but it is simply _not_ 
what the word means in any other context.)

It is true that the inner, hidden, memory area (static array) containing the 
elements is indeed referenced, actually "pointed", from the dynamic array 
struct:

struct ValueArray(Element) {
    Element* elements;
    uint length;
}
(Well, actually, this may not be a struct, but it's easier to imagine it so.)

But: the dyn array itself, meaning the struct, is not referenced: "a2 = a1" 
copies it, as well as parameter passing. And the fact that the internal memory 
is referenced is an implementation detail that should *not* affect semantics. 
The inner pointer is there because we need some kind of indirection to 
implement variable-size thingies, and the means for this is pointers.
This is precisely where & why people get bitten: implementation leaks out into 
semantics.
Actually, one could conceptually replace the (pointer,length) pair by a single 
field of type MemoryArea -- which would be a plain value. Then, there would be 
no more (visible) pointer in the dyn array, right? (Actually, it would just be 
hidden deeper inside the MemoryArea field... but that is again implementation 
detail!)

We should not mess up pointers used for implementation mechanics, like in the 
case of dyn arrays, or more generally variable size data structure, with 
pointers used as true references carrying semantics, like in the case of the 
difference between struct and class.

And precisely, replacing array struct by a class, or explicitely referencing 
the struct, would make a *reference* dyn array type. See below an example of a 
primitive sort of such an array type (you can only put new elements in it ;-), 
implemented as class.
After "a2 = a1", every change to one of the vars affects the other var; whether 
the change requires reallocation is irrelevant; this detail belongs to 
implementation, not to semantics.
Now, replace class with struct and you have a type for *value* dyn arrays. 
Which works exactly like D ones.
The assertion will fail; and output should be interesting ;-)

Hope it's clear, because I cannot do better.
I do not mean that D arrays are bad in any way. They work perfectly and are 
very efficient. Enforcing a true interface between implementation and semantics 
would certainly have a relevant cost in terms of space & time. But please, stop 
stating D arrays are referenced if you want newcomers to have a chance & 
understand the actual behaviour, to use them without beeing constantly bitten, 
and to stop & complain.


Denis

class RefArray(Element) {
    Element* elements;
    uint length;
    private uint capacity;
    this () {
        this.elements = cast(Element*) malloc(Element.sizeof);
        this.capacity = 1;
        this.length = 0;
    }
    void reAlloc() {
        writeln("realloc");
        this.capacity *= 2;
        size_t memSize = this.capacity * Element.sizeof;
        realloc(this.elements, memSize);
    }
    void put(Element element) {
        if (this.length >= this.capacity)
            this.reAlloc();
        this.elements[this.length] = element;
        ++ this.length;
    }
    void opBinary(string op) (Element element)
    if (op == "+") {
        this.put(element);
    }
}

void main () {
    auto a1 = new RefArray!int();
    auto a2 = a1;
    foreach (int i ; 1..8) {a2.put(i);}
    assert(a1.length == a2.length);
    foreach (int i ; 0 .. a2.length)
        writef("%s=%s ", a1.elements[i], a2.elements[i]);
    writeln();
    a1 + 8; a1 + 9;
    foreach (int i ; 0 .. a2.length)
        writef("%s=%s ", a1.elements[i], a2.elements[i]);
    writeln();
}
-- -- -- -- -- -- --
vit esse estrany ☣

spir.wikidot.com

Reply via email to