BIg semantic issues with SList & DList

monarch_dodra monarchdodra at gmail.com
Wed Sep 12 10:25:18 PDT 2012


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.


More information about the Digitalmars-d mailing list