On 2010-12-15 00:19, Graham St Jack wrote:

I don't know, do you have an example ?

For example taking a classname and a bunch of field types and names, and
turning it into a class definition complete with constructor from field
values, constructor from an input stream, a method to write to an output
stream, and const getters. Or maybe std.typecons.AutoImplement.

Could you post an example of how that mixin would be used and the code
it would generate then I can see if I can translate it to my syntax.
AutoImplement seems to just contain template mixins which is something
else.


I have attached my concurrency framework, which relies heavily on
mixins, plus its unit test to show how it is used. I haven't included
the various dependencies because I assume you just want the example
code. Let me know if you want something buildable, or perhaps something
more cut-down.

What the code-generating template does is to create from something like
this (you can have any number of Messages in a Protocol):


alias Protocol!("Requests", Message!("job", string, "name")).code jobCode;
mixin(jobCode);


this code:


class Requests {
struct jobMsg {
string name;
this(string name) {
this.name = name;
}
void read(InStream stream) {
name = stream.get!string;
}
void write(OutStream stream) {
stream(name);
}
}
struct Message {
uint kind;
union {
jobMsg job;
}
this(ref jobMsg msg) {
kind = 0;
job = msg;
}
this(InStream stream) {
kind = stream.get!uint;
switch(kind) {
case 0: job.read(stream); break;
default: assert(0, "Cannot read unsupported message kind");
}
}
void write(OutStream stream) {
stream(kind);
switch(kind) {
case 0: job.write(stream); break;
default: assert(0, "Cannot write unsupported message kind");
}
}
}
private alias Channel!(Message) _Chan;
private alias shared _Chan Chan;

private Chan channel;
this() { channel = new Chan(); }
ChannelSelectable newSelectable() { return channel.newSelectable(); }
void finalize() { channel.finalize; }

interface IHandler {
void job(string name);
}
void job(string name) {
channel.add(Message(jobMsg(name)));
}
void receive(IHandler handler) {
auto message = channel.remove;
switch (message.kind) {
case 0: handler.job(message.job.name); break;
default: assert(0, "Cannot dispatch unsupported message kind");
}
}
}



I use this for inter-thread communications, and I use the discriminated
union to pass messages between processes. The manual mixin after the
alias is a debugging aid - the compiler errors when doing mixins aren't
helpful at all. I case you are wondering why I did all this, it was
partly a learning experience, but mostly an attempt to do something
properly thread-safe (!hasAliasing), using shared, const and immutable
properly.

I've attached a part of how concurrency.d could look like translated to my suggested syntax. It probably contains a lot of errors because did a quick translation and I had some trouble understanding the mixins.

--
/Jacob Carlborg
void delegate () Paste (string name, string joiner)
{
        return
        {
                static if (more)
                        enum @name = { _...@name @joiner Next.name; };
                        
                else
                        enum @name = { _...@name; };
        }
}

private template MessageStrings(string msgName, T...) {
    static assert(T.length > 1, "Message parameters must be in pairs");
    enum more = T.length > 2;
    static if (more) {
        alias MessageStrings!(msgName, T[2..$]) Next;
    }
    static if (T.length > 0) {
        static assert(!hasAliasing!(T[0]), "Cannot use type " ~ T[0].stringof ~ 
" in a message");
        static assert(is(typeof(T[1]) : string), "Message parameters must be 
named");

                enum _fieldStr = { @(T[0].stringof) @T[1]; };
                enum _initStr = { th...@t[1] = @T[1]; }
                enum _readStr = { @t[1] = stream.g...@t[0].stringof; }
                enum _writeStr = { (@T[1]) };
                
                enum _paramStr = { @(T[0].stringof) @T[1]; };
                enum _nameStr = {�...@t[1]; };
                enum _callStr = { messa...@msgname.@T[1]; };

                @Paste("fieldStr", "\n    ");     // field types and names in 
definition
                @Paste("initStr",  "\n        "); // field assignments in 
constructor
                @Paste("readStr",  "\n        "); // fields read from an 
InStream
                @Paste("writeStr", "");           // fields written to an 
OutStream

                @Paste("paramStr", ", ");         // field types and names, 
comma-separated
                @Paste("nameStr",  ", ");         // field names, comma 
separated
                @Paste("callStr",  ", ");         // field values accessed in 
an enclosing union, comma separated
    }
}

void delegate () Messages (T...) (string name)
{
        static assert(T.length > 0, "Messages have to contain fields");

    alias name msgName;

    alias MessageStrings!(name, T) strings;

        return
        {
                struct @(name)Msg
                {
                        @strings.fieldStr;
                        
                        this (@strings.paramStr)
                        {
                                @strings.initStr;
                        }
                        
                        void read (InStream stream)
                        {
                                @strings.readStr;
                        }
                        
                        void write (OutStream stream)
                        {
                                str...@strings.writestr;
                        }
                }
        };
}

Reply via email to