Re: Semi Automated Object wrapping

2009-08-13 Thread Bill Baxter
On Thu, Aug 13, 2009 at 12:43 AM, Rory McGuirerjmcgu...@gmail.com wrote:
 On Wed, 12 Aug 2009 17:03:17 -0700, Bill Baxter wrote:

 On Wed, Aug 12, 2009 at 4:52 PM, Rory McGuirerjmcgu...@gmail.com
 wrote:
 Here is some code I wrote which enables wrapping a proxy around an
 object. I am using it for my serialization library. It works in
 D1(1.046) and D2 (2.031)

 Posting it here for reference by all before I add to much of the stuff
 specific to my use, should make it easier to follow.

 usage: new ProxyClass!(A, cast(string)getInt setInt getString); would
 implement the methods getInt setInt and getString from A in the new
 class.

 the code below will fail to compile but not before printing the
 generated code to stdout.

 Shin Fujishiro has made some new templates for D2 which will make it so
 I can get rid of the setInt getInt getString part which would make
 the usage for D2: new ProxyClass!A;
 which would be great!

 -Rory

  // author: Rory McGuire,
 rjmcgu...@gmail.com import std.stdio;
 import std.typetuple;
 import std.traits;
 import std.metastrings;

 //import serializer;

 // this CTF from somewhere on news.digitalmars.com string[]
 splitFuncs(string str) {
    string[] res;
    while (str.length  0) {
        while (str.length  0  (' ' == str[0] || ',' == str[0])) {
            str = str[1..$];
        }
        int to = 0;
        for (; to  str.length  str[to] != ' '  str[to] != ',';
        ++to)
 {}
        if (to  0) {
            res ~= str[0..to];
            str = str[to..$];
        }
    }
    return res;
 }

 string MethodTypeTuple_mixin(alias a)(string[] methods) {
        string ret = TypeTuple!(~
        typeof(C.init.~methods[0]~); foreach (method;
        methods[1..$]) {
                ret ~= ,typeof(C.init.~method~);
        }
        ret ~= );
        return ret;
 }



 // test case

 class A {
        int a;
        this(int a) {
                this.a = a;
        }
        int getInt(string intname) {
                return a;
        }

        void setInt(int i) {
                a = i;
        }
        string getString(string s) {
                return s ~1234;
        }
 }


 string ProxyMethods_mixin(alias C, string methodstr)() {
        string ret;
        foreach(i, t; mixin(MethodTypeTuple_mixin!(C)(splitFuncs
 (methodstr {
                // output function header
                ret ~= \t~ReturnType!(t).stringof ~ ~
                splitFuncs
 (methodstr)[i]~(;
                // output first arg
                ret ~= ParameterTypeTuple!(t)[0].stringof~
                arg; // output remainder of args
                foreach (j, t1; ParameterTypeTuple!(t)[1..$]) {
                        ret ~= ,~t1.stringof~
 arg~std.metastrings.ToString!(j);
                }
                // output body
                ret ~= ) {\n;
                // output serialization code
                // send method name
                ret ~= \t\twritefln(\serialize docall id\);
                // the
 method call byte id\n;
                ret ~= \t\tbuffer ~=
                serialize!(string)(\~splitFuncs
 (methodstr)[i]~\, s_state); /+ the method name +/\n;
                // send args
                ret ~= \t\tbuffer ~= serialize!(~
                ParameterTypeTuple!(t)
 [0].stringof~)(arg, s_state); /+ the first argument +/\n;
                foreach (j, t1; ParameterTypeTuple!(t)[1..$]) {
                        ret ~= \t\tbuffer ~= serialize!(~
                        t1.stringof
 ~)(arg~ToString!(j)~, s_state); /+ argument ~ToString!(j)~ +/\n;
                }
                // receive return type
                static if (!is(ReturnType!(t) == void)) {
                        ret ~= \t\treturn deserialize!(~
                        ReturnType!
 (t).stringof ~)(buffer, des_state);\n;
                }
                ret ~= \t}\n;
        }
        return ret;
 }


 class ProxyClass(alias C, string methodstr) {
                ubyte[] buffer;
                mixin(ProxyMethods_mixin!(C,methodstr)());
                pragma(msg, class ProxyClass!(~C.stringof~,
                \~
 methodstr ~\) {\n\tubyte[] buffer;\n  SerializerState s_state;\n
 DeserializerState des_state;\n  this() {s_state = new
 SerializerState(); des_state = new DeserializerState(); }\n\n~
 ProxyMethods_mixin! (C,methodstr)() ~\n}\n);

 }

 void main() {
        auto pc = new ProxyClass!(A, cast(string)getInt setInt
 getString);
        writefln(ProxyClass: ~ pc.getString(asdf));
 }


 That code is screaming for some macros. Or variable interpolation at
 least.

 --bb

 Where would you propose that one would use 'macro'?


It doesn't exist yet, so there's not much you can do about it.
Unfortunately code that generates code in D pretty much has to look
like what you wrote there.  I'm just saying it's not a lot of fun to
read such code.  Compare with Lisp macros that are almost as readable
as regular Lisp functions.

Or maybe instead of macros, 

Re: Semi Automated Object wrapping

2009-08-13 Thread Daniel Keep


Bill Baxter wrote:
 On Thu, Aug 13, 2009 at 12:43 AM, Rory McGuirerjmcgu...@gmail.com wrote:
 On Wed, 12 Aug 2009 17:03:17 -0700, Bill Baxter wrote:

 On Wed, Aug 12, 2009 at 4:52 PM, Rory McGuirerjmcgu...@gmail.com
 wrote:
 Here is some code I wrote which enables wrapping a proxy around an
 object. I am using it for my serialization library. It works in
 D1(1.046) and D2 (2.031)

 Posting it here for reference by all before I add to much of the stuff
 specific to my use, should make it easier to follow.

 usage: new ProxyClass!(A, cast(string)getInt setInt getString); would
 implement the methods getInt setInt and getString from A in the new
 class.

 the code below will fail to compile but not before printing the
 generated code to stdout.

 Shin Fujishiro has made some new templates for D2 which will make it so
 I can get rid of the setInt getInt getString part which would make
 the usage for D2: new ProxyClass!A;
 which would be great!

 -Rory

  // author: Rory McGuire,
 rjmcgu...@gmail.com import std.stdio;
 import std.typetuple;
 import std.traits;
 import std.metastrings;

 //import serializer;

 // this CTF from somewhere on news.digitalmars.com string[]
 splitFuncs(string str) {
string[] res;
while (str.length  0) {
while (str.length  0  (' ' == str[0] || ',' == str[0])) {
str = str[1..$];
}
int to = 0;
for (; to  str.length  str[to] != ' '  str[to] != ',';
++to)
 {}
if (to  0) {
res ~= str[0..to];
str = str[to..$];
}
}
return res;
 }

 string MethodTypeTuple_mixin(alias a)(string[] methods) {
string ret = TypeTuple!(~
typeof(C.init.~methods[0]~); foreach (method;
methods[1..$]) {
ret ~= ,typeof(C.init.~method~);
}
ret ~= );
return ret;
 }



 // test case

 class A {
int a;
this(int a) {
this.a = a;
}
int getInt(string intname) {
return a;
}

void setInt(int i) {
a = i;
}
string getString(string s) {
return s ~1234;
}
 }


 string ProxyMethods_mixin(alias C, string methodstr)() {
string ret;
foreach(i, t; mixin(MethodTypeTuple_mixin!(C)(splitFuncs
 (methodstr {
// output function header
ret ~= \t~ReturnType!(t).stringof ~ ~
splitFuncs
 (methodstr)[i]~(;
// output first arg
ret ~= ParameterTypeTuple!(t)[0].stringof~
arg; // output remainder of args
foreach (j, t1; ParameterTypeTuple!(t)[1...$]) {
ret ~= ,~t1.stringof~
 arg~std.metastrings.ToString!(j);
}
// output body
ret ~= ) {\n;
// output serialization code
// send method name
ret ~= \t\twritefln(\serialize docall id\);
// the
 method call byte id\n;
ret ~= \t\tbuffer ~=
serialize!(string)(\~splitFuncs
 (methodstr)[i]~\, s_state); /+ the method name +/\n;
// send args
ret ~= \t\tbuffer ~= serialize!(~
ParameterTypeTuple!(t)
 [0].stringof~)(arg, s_state); /+ the first argument +/\n;
foreach (j, t1; ParameterTypeTuple!(t)[1...$]) {
ret ~= \t\tbuffer ~= serialize!(~
t1.stringof
 ~)(arg~ToString!(j)~, s_state); /+ argument ~ToString!(j)~ +/\n;
}
// receive return type
static if (!is(ReturnType!(t) == void)) {
ret ~= \t\treturn deserialize!(~
ReturnType!
 (t).stringof ~)(buffer, des_state);\n;
}
ret ~= \t}\n;
}
return ret;
 }


 class ProxyClass(alias C, string methodstr) {
ubyte[] buffer;
mixin(ProxyMethods_mixin!(C,methodstr)());
pragma(msg, class ProxyClass!(~C.stringof~,
\~
 methodstr ~\) {\n\tubyte[] buffer;\n  SerializerState s_state;\n
 DeserializerState des_state;\n  this() {s_state = new
 SerializerState(); des_state = new DeserializerState(); }\n\n~
 ProxyMethods_mixin! (C,methodstr)() ~\n}\n);

 }

 void main() {
auto pc = new ProxyClass!(A, cast(string)getInt setInt
 getString);
writefln(ProxyClass: ~ pc.getString(asdf));
 }


 That code is screaming for some macros. Or variable interpolation at
 least.

 --bb
 Where would you propose that one would use 'macro'?

 
 It doesn't exist yet, so there's not much you can do about it.
 Unfortunately code that generates code in D pretty much has to look
 like what you wrote there.  I'm just saying it's not a lot of fun to
 read such code.  Compare with Lisp macros that are almost as readable
 as regular Lisp functions.
 
 

Re: Semi Automated Object wrapping

2009-08-12 Thread Bill Baxter
On Wed, Aug 12, 2009 at 4:52 PM, Rory McGuirerjmcgu...@gmail.com wrote:
 Here is some code I wrote which enables wrapping a proxy around an object.
 I am using it for my serialization library. It works in D1(1.046) and D2
 (2.031)

 Posting it here for reference by all before I add to much of the stuff
 specific to my use, should make it easier to follow.

 usage: new ProxyClass!(A, cast(string)getInt setInt getString); would
 implement the methods getInt setInt and getString from A in the new class.

 the code below will fail to compile but not before printing the generated
 code to stdout.

 Shin Fujishiro has made some new templates for D2 which will make it so I
 can get rid of the setInt getInt getString part which would make the
 usage for D2: new ProxyClass!A;
 which would be great!

 -Rory

 
 // author: Rory McGuire, rjmcgu...@gmail.com
 import std.stdio;
 import std.typetuple;
 import std.traits;
 import std.metastrings;

 //import serializer;

 // this CTF from somewhere on news.digitalmars.com
 string[] splitFuncs(string str) {
    string[] res;
    while (str.length  0) {
        while (str.length  0  (' ' == str[0] || ',' == str[0])) {
            str = str[1..$];
        }
        int to = 0;
        for (; to  str.length  str[to] != ' '  str[to] != ','; ++to)
 {}
        if (to  0) {
            res ~= str[0..to];
            str = str[to..$];
        }
    }
    return res;
 }

 string MethodTypeTuple_mixin(alias a)(string[] methods) {
        string ret = TypeTuple!(~ typeof(C.init.~methods[0]~);
        foreach (method; methods[1..$]) {
                ret ~= ,typeof(C.init.~method~);
        }
        ret ~= );
        return ret;
 }



 // test case

 class A {
        int a;
        this(int a) {
                this.a = a;
        }
        int getInt(string intname) {
                return a;
        }

        void setInt(int i) {
                a = i;
        }
        string getString(string s) {
                return s ~1234;
        }
 }


 string ProxyMethods_mixin(alias C, string methodstr)() {
        string ret;
        foreach(i, t; mixin(MethodTypeTuple_mixin!(C)(splitFuncs
 (methodstr {
                // output function header
                ret ~= \t~ReturnType!(t).stringof ~ ~ splitFuncs
 (methodstr)[i]~(;
                // output first arg
                ret ~= ParameterTypeTuple!(t)[0].stringof~ arg;
                // output remainder of args
                foreach (j, t1; ParameterTypeTuple!(t)[1..$]) {
                        ret ~= ,~t1.stringof~
 arg~std.metastrings.ToString!(j);
                }
                // output body
                ret ~= ) {\n;
                // output serialization code
                // send method name
                ret ~= \t\twritefln(\serialize docall id\); // the
 method call byte id\n;
                ret ~= \t\tbuffer ~= serialize!(string)(\~splitFuncs
 (methodstr)[i]~\, s_state); /+ the method name +/\n;
                // send args
                ret ~= \t\tbuffer ~= serialize!(~ ParameterTypeTuple!(t)
 [0].stringof~)(arg, s_state); /+ the first argument +/\n;
                foreach (j, t1; ParameterTypeTuple!(t)[1..$]) {
                        ret ~= \t\tbuffer ~= serialize!(~ t1.stringof
 ~)(arg~ToString!(j)~, s_state); /+ argument ~ToString!(j)~ +/\n;
                }
                // receive return type
                static if (!is(ReturnType!(t) == void)) {
                        ret ~= \t\treturn deserialize!(~ ReturnType!
 (t).stringof ~)(buffer, des_state);\n;
                }
                ret ~= \t}\n;
        }
        return ret;
 }


 class ProxyClass(alias C, string methodstr) {
                ubyte[] buffer;
                mixin(ProxyMethods_mixin!(C,methodstr)());
                pragma(msg, class ProxyClass!(~C.stringof~, \~
 methodstr ~\) {\n\tubyte[] buffer;\n  SerializerState s_state;\n
 DeserializerState des_state;\n  this() {s_state = new SerializerState();
 des_state = new DeserializerState(); }\n\n~ ProxyMethods_mixin!
 (C,methodstr)() ~\n}\n);

 }

 void main() {
        auto pc = new ProxyClass!(A, cast(string)getInt setInt
 getString);
        writefln(ProxyClass: ~ pc.getString(asdf));
 }


That code is screaming for some macros.
Or variable interpolation at least.

--bb