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