Basically, the problem is that their copy semantics adhere to neither value nor reference semantics. The embody a "reference to a third party chain system" semantic.

Erm... What does this mean?

Basically, a "chain of nodes is created", and the lists reference points in that chain, but not necessarily the beginnings nor ends. How is this a problem? I'll start with SList:

SList
--------
import std.stdio, std.container, std.range, std.iostream, std.algorithm;
void main()
{
    auto a = SList!int([3, 4]);
    auto b = a;
    // ab -> 3 -> 4 -> null
    assert(a[].equal([3, 4]));
    assert(b[].equal([3, 4]));
    a.stableInsertFront(1);
    b.stableInsertFront(2);
    // a -> 1
    //       \
    //        3 -> 4 -> null
    //       /
    // b -> 2
    assert(a[].equal([1, 3, 4]));
    assert(b[].equal([2, 3, 4]));

    //a: change the 2nd element (4) into 5;
    a[].drop(2).front = 5;
    // a -> 1
    //       \
    //        3 -> 5 -> null
    //       /
    // b -> 2
    assert(a[].equal([1, 3, 5]));
    assert(b[].equal([2, 3, 5]));

    a.clear();
    // a -> null
    //
    //        3 -> 4 -> null
    //       /
    // b -> 2
    assert(a[].empty);
    assert(b[].equal([2, 3, 5]));

    a.insert(1);
    // -> 1 -> null
    //
    //      3 -> 5-> null
    //     /
    // -> 2
    assert(a[].equal([1]));
    assert(b[].equal([2, 3, 5]));
}
--------
Is this a clear example of what I mean?
NOW: The big question:

IS THIS A LEGITIMATE BEHAVIOR?

IMO, for SList, yes, yes it is. _HOWEVER_, it must be much clearly documented in the docs, as well as examples provided.

I have done some relatively heavy testing, and I have found no bugs in SList.

However, there are a couple *Gotcha's*, in particular, regarding the effects of "remove": Are we merely advancing the SList's "root pointer", or actually excising elements from the "chain" itself? Depends on context :D but nothing that can't be documented.

DLists has the same semantic:
--------
import std.stdio, std.container, std.range, std.algorithm;
void main()
{
    auto a = DList!int([3, 4]);
    auto b = a;
    // (3 - 4)
    assert(a[].equal([3, 4]));
    assert(b[].equal([3, 4]));

    b.stableInsertFront(1);
    b.stableInsertBack(5);
    // (2 - (3 - 4) - 5)
    assert(a[].equal([3, 4]));
    assert(b[].equal([1, 3, 4, 5]));

    a.stableInsertFront(2);
    // (1 - (2 - 3 - 4) - 5)
    assert(a[].equal([2, 3, 4]));
    writeln(b[]);
    assert(b[].equal([1, 2, 3, 4, 5]));

    //Does not work as expected!
    a.remove(a[]);
    writeln(a[]); //[2, 3, 4]
    writeln(b[]); //[1, 5]
}
--------
The example stops here, because DList was obviously written without this in mind. I don't have enough fingers on my hands to list the use-cases that break it.

Again, same question:

IS THIS A LEGITIMATE BEHAVIOR?

The gotchas are even more prevalent here. Not only gotchas, but just plain problems regarding theoretical behavior: What does it mean to append two DLists, if those DLists are views into two different, but, bigger, chains?

IMO: For DList, it is just too damn complicated to keep this semantic. I'd migrate to "true reference".


--------
The good news is that having "true" reference semantics with {SD}List should be relatively easy. Depending on the output of this discussion, it is something <s>I wouldn't mind</s> I'd enjoy doing.

TY for reading.

Reply via email to