On 02.11.2010 0:24, bearophile wrote:
To answer the recent D.learn thread "How would I optimize this parser?", I have 
tried to find a more efficient way to build the parse tree, so I have used tagged 
structs, something like this:


enum NodeType { node, text, tag }

struct Node {
     /*immutable*/ NodeType type = NodeType.node;
     Node* parent;
}

struct TextNode {
     /*immutable*/ NodeType type = NodeType.text;
     Node* parent;
     string content;

     public nothrow this(string content) {
         this.content = content;
     }
}

struct TagNode {
     /*immutable*/ NodeType type = NodeType.tag;
     Node* parent;
     string name;
     Node*[] children;

     public nothrow this(string name) {
         this.name = name;
     }

     public nothrow void addChild(Node* newChild) {
         children ~= newChild;
         newChild.parent = cast(Node*)&this;
     }
}


Each struct instance contains a "type" tag that at runtime tells what kind of 
node it is. This tag never changes in the life of a node, so it's better for it to be 
immutable, to use the type system to avoid changing it by mistake.

But unfortunately it doesn't work, this is a reduced example:


struct Foo {
     immutable int x = 1;
}
struct Bar {
     immutable int x = 2;
}
static assert(Foo.sizeof == 4);
void main() {
     Foo f;
     assert(f.x == 1);
     assert((cast(Bar)f).x == 1);
}


It seems that immutable fields act like static const fields or enum fields, 
they have no storage. This seems a little weird to me. Do you know a way to put 
immutable storage in a struct instance?

Using this doesn't work:

this(int) { type = NodeType.tag; }

And a static this() doesn't seem to work. So in the program I have just used a 
mutable type field, but it looks silly...

Bye,
bearophile
Wierd indeed, best workaround I can come up with:
struct Foo {
    immutable int x;
    private this(int val){ x = val; }
    public  static Foo opCall(){
         return Foo(1);
    }
}
struct Bar {
    immutable int x;
    private this(int val){ x = val; }
    public  static Bar opCall(){
         return Bar(2);
    }

}
static assert(Foo.sizeof == 4);
void main() {
    Foo f = Foo();
    assert(f.x == 1);
    assert((cast(Bar*)&f).x == 1);
}

works, and the fact that static opCall is deprecated(?) makes me wish it's a compiler bug. And you still could shoot yourself in the leg, but only explicitly (that is "Foo f = Foo(42)" ) and only in the same module.

--
Dmitry Olshansky

Reply via email to