On 1/14/15 10:09 AM, Ali Çehreli wrote:
On 01/14/2015 02:53 AM, ketmar via Digitalmars-d wrote:

 > On Wed, 14 Jan 2015 10:41:07 +0000
 > qqiang via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
 >
 >> template PowerHeap(T) {
 >>       import std.container : SList;
 >>
 >>       private alias PowerForest = SList!PowerNode;
 >>
 >>       private final class PowerNode {
 >>           private {
 >>               T payload_;
 >>               uint rank_;
 >>               PowerForest children_;
 >>           }
 >>       }
 >>
 >>       final class PowerHeap {
 >>           private {
 >>               PowerNode top_;
 >>               PowerForest forest_;
 >>               uint size_;
 >>           }
 >>       }
 >> }
 >>
 >> unittest {
 >>       PowerHeap!int h;
 >> }
 > there is a circular dependency in your data structures. you're defining
 > `PowerNode` in the terms of... `PowerNode`. this won't work.
 >
 > your `PowerForest` definition depends of complete `PowerNode`
 > definition, but `PowerNode` definition depends of complete
 > `PowerForest` definition.
 >
 > don't do that.
 >

Reduced:

import std.container;

class Node
{
     SList!Node children;
}

void main()
{}

Error: class deneme.Node no size yet for forward reference

I wonder why an SList of a reference type requires the size of the
elements? The following compiles but is that a pointer to a class
variable or a class object? How can we even use the 'children' member?

     SList!(Node*) children;

Ali


In my not-so-expert opinion, I think this is somewhat of a bug, but not in the compiler. Note that it depends heavily on the definition of SList. If SList starts using pieces of S, it may confuse or create issues with the compiler.

A simple test is to declare an opaque class:

class S;

void main()
{
   S foo;
}

This works (at least it works to compile, not to link as the linker can't find the class symbol)

Now, if I do this:

import std.container;

class S;

alias listofs = SList!S;

void main()
{
   S foo;
}

I get the following audit from the compiler:

/usr/share/dmd/src/phobos/std/traits.d(2032): Error: class testforward.S unknown size /usr/share/dmd/src/phobos/std/traits.d(2198): Error: template instance std.traits.FieldTypeTuple!(S) error instantiating /usr/share/dmd/src/phobos/std/traits.d(2349): instantiated from here: RepresentationTypeTuple!(S) /usr/share/dmd/src/phobos/std/traits.d(2692): instantiated from here: hasRawAliasing!(S) /usr/share/dmd/src/phobos/std/algorithm.d(1888): instantiated from here: hasAliasing!(S) /usr/share/dmd/src/phobos/std/container.d(1008): Error: template instance std.algorithm.move!(S) error instantiating
testforward.d(4):        instantiated from here: SList!(S)
/usr/share/dmd/src/phobos/std/range.d(3149): Error: template instance std.range.hasAssignableElements!(Range) error instantiating /usr/share/dmd/src/phobos/std/container.d(1359): Error: template instance std.range.Take!(Range) error instantiating
testforward.d(4):        instantiated from here: SList!(S)


So I think it's SList's invocation of move, which in turn checks hasAliasing, which in turn needs S's total definition (as it starts getting the fields of S). I think hasAliasing!(someclass) needs to be short circuited to true, or slist needs to use some other mechanism. I don't know how SList works exactly, maybe it does not actually allocate a list of class references, but instead emplaces them. In that case, you may be out of luck.

-Steve

Reply via email to