digitalmars.D.learn - Q: Populating a structure with RTTI
- Myron Alexander (23/23) Jun 10 2007 Hello.
- Chris Nicholson-Sauls (10/43) Jun 10 2007 T populate (T) () {
- Myron Alexander (12/101) Jun 11 2007 Thanks Chris.
- Lutger (4/9) Jun 11 2007 You can use foreach on tuples:
- Lutger (21/32) Jun 11 2007 I missed the other one, this could be done in a similar fashion, for
- Myron Alexander (22/49) Jun 11 2007 Thanks. I can't make use of that as the fetch is a generic fetch from a
- Myron Alexander (10/202) Jun 11 2007 I received the answer in another thread so I have a functional spike.
- Myron Alexander (5/156) Jun 11 2007 Thanks Lutger. One down, one to go.
- BLS (11/44) Jun 11 2007 Hi Myron,
- BLS (52/85) Jun 11 2007 Hi Myron, I think my previous suggestion will not work; (compiletime iss...
- Myron Alexander (12/13) Jun 11 2007 Hello Bjoern.
Hello.
Is it possible to populate a struct using RTTI?
Example:
Say I have a struct as such:
struct Example {
int x;
int y;
char[] z;
}
and I want to create and populate the structure from a function:
T populate(T) () {
T t;
t.field[0] = 1;
t.field[1] = 2;
t.field[2] = "testing";
return t;
}
void main() {
auto x = populate!(Example)();
}
Is this possible? If so, what is the syntax?
Thanks ahead,
Myron.
Jun 10 2007
Myron Alexander wrote:
Hello.
Is it possible to populate a struct using RTTI?
Example:
Say I have a struct as such:
struct Example {
int x;
int y;
char[] z;
}
and I want to create and populate the structure from a function:
T populate(T) () {
T t;
t.field[0] = 1;
t.field[1] = 2;
t.field[2] = "testing";
return t;
}
void main() {
auto x = populate!(Example)();
}
Is this possible? If so, what is the syntax?
Thanks ahead,
Myron.
T populate (T) () {
T t;
t.tupleof[0] = 1;
t.tupleof[1] = 2;
t.tupleof[2] = "testing";
return t;
}
Although its dangerous, but I'm sure you knew that already.
-- Chris Nicholson-Sauls
Jun 10 2007
Chris Nicholson-Sauls wrote:T populate (T) () { T t; t.tupleof[0] = 1; t.tupleof[1] = 2; t.tupleof[2] = "testing"; return t; } Although its dangerous, but I'm sure you knew that already. -- Chris Nicholson-SaulsThanks Chris. I do have another problem that you may be able to help me with. Here is an example of how I would use the above:import std.stdio; import std.traits; /* Example value object. */ struct ValueStruc { char[] name; int age; char[] addr1; char[] addr2; char[] addr3; double balance; } /* Typesafe database row object. */ struct Row(T ...) { T t; bool[T.length] nullFlag; } /* Simulate a typesafe fetch from the database. */ Row!(T) fetchOne(T ...) () { Row!(T) r; /+ Won't compile: int i = 0; r.t[i++] = "Myron"; r.t[i++] = 10; r.t[i++] = "addr1"; r.t[i++] = "addr2"; r.t[i++] = "addr3"; r.t[i++] = 100001.10; +/ r.t[0] = "Myron"; r.t[1] = 10; r.t[2] = "addr1"; r.t[3] = "addr2"; r.t[4] = "addr3"; r.t[5] = 100001.10; r.nullFlag[0] = false; r.nullFlag[1] = true; r.nullFlag[2] = false; return r; } /* Fetch a typesafe record from the database and populate the struct. */ T fetchStruc(T) () { static if (is (T == struct)) { auto r = fetchOne!(FieldTypeTuple!(T))(); T t; /+ Won't compile: for (int i = 0; i < T.tupleof.length; i++) { t.tupleof[i] = r.t[i]; } +/ // My nasty hack to get it to work: static if ( 0 < T.tupleof.length) t.tupleof[0] = r.t[0]; static if ( 1 < T.tupleof.length) t.tupleof[1] = r.t[1]; static if ( 2 < T.tupleof.length) t.tupleof[2] = r.t[2]; static if ( 3 < T.tupleof.length) t.tupleof[3] = r.t[3]; static if ( 4 < T.tupleof.length) t.tupleof[4] = r.t[4]; static if ( 5 < T.tupleof.length) t.tupleof[5] = r.t[5]; return t; } else { static assert (0); } } void main () { auto x = fetchStruc!(ValueStruc) (); x.addr3, x.balance); }I would like to implement the "Won't compile" blocks but have no clue if it is even possible. I'm thinking either a mixin, or a compile time function or something to that effect would allow me to build the functions so I don't have to use a whole whackload of static ifs as I have done in the fetchStruc. If I can get this right, would make my normal use-case much easier. Thanks, Myron.
Jun 11 2007
Myron Alexander wrote:You can use foreach on tuples: foreach(index, value; r.t) t.tupleof[index] = value;/+ Won't compile: for (int i = 0; i < T.tupleof.length; i++) { t.tupleof[i] = r.t[i]; } +/
Jun 11 2007
Lutger wrote:Myron Alexander wrote:I missed the other one, this could be done in a similar fashion, for example: /+ Won't compile: int i = 0; r.t[i++] = "Myron"; r.t[i++] = 10; r.t[i++] = "addr1"; r.t[i++] = "addr2"; r.t[i++] = "addr3"; r.t[i++] = 100001.10; +/ with a helper function: void populateRow(R, T...)(inout R r, T t) { static assert(is(typeof(r.t) == T)); foreach(index, value; t) r.t[index] = value; } inside fetchOne: populateRow(r, "Myron"[], 10, "addr1"[], "addr2"[], "addr3"[], 100001.10);You can use foreach on tuples: foreach(index, value; r.t) t.tupleof[index] = value;/+ Won't compile: for (int i = 0; i < T.tupleof.length; i++) { t.tupleof[i] = r.t[i]; } +/
Jun 11 2007
Lutger wrote:
I missed the other one, this could be done in a similar fashion, for
example:
/+ Won't compile:
int i = 0;
r.t[i++] = "Myron";
r.t[i++] = 10;
r.t[i++] = "addr1";
r.t[i++] = "addr2";
r.t[i++] = "addr3";
r.t[i++] = 100001.10;
+/
with a helper function:
void populateRow(R, T...)(inout R r, T t)
{
static assert(is(typeof(r.t) == T));
foreach(index, value; t)
r.t[index] = value;
}
inside fetchOne:
populateRow(r, "Myron"[], 10, "addr1"[], "addr2"[], "addr3"[], 100001.10);
Thanks. I can't make use of that as the fetch is a generic fetch from a
database so it does not know the number of parameters upfront.
This is an example of what I would like to do:
for (int i = 0; i < r.t.length; i++) {
getByType (i, r.t[i]);
}
Where getByType is a method on the statement object that get's the i'th
column and sets r.t[i].
getByType (int i, ref int value);
getByType (int i, ref long value);
getByType (int i, ref char[] value);
...
That is just a paradigm example, it could also be written using:
for (int i = 0; i < r.t.length; i++) {
if (r.t[i].type = typeid (int) {
r.t[i] = getInt (i);
} else if ...
}
Any ideas?
Thanks,
Myron.
Jun 11 2007
I received the answer in another thread so I have a functional spike.
I just want to thank Chris Nicholson-Sauls, Lutger Blijdestijn, and
Christian Kam for the help. Without you guys this would not have been
possible.
I am so excited now and if the concept pans out, I think I may explode :)
Just one last thing, what do you think of the type-safe fetch idea,
something that will make your lives easier, or just another WTF?
Best Regards,
Myron.
Here is the final spike in full:
import std.stdio;
import std.traits;
import std.conv;
/* Example value object.
*/
struct ValueStruc {
char[] name;
int age;
char[] addr1;
char[] addr2;
char[] addr3;
double balance;
}
struct OtherValue {
int type;
char[] dirname;
char[] filename;
}
struct ValueStrucWNull {
char[] name;
int age;
char[] addr1;
char[] addr2;
char[] addr3;
double balance;
bool[6] nullFlag;
}
struct OtherValueWNull {
int type;
char[] dirname;
char[] filename;
bool[3] nullFlag;
}
/* Typesafe database row object.
*/
struct Row(T ...) {
T t;
bool[T.length] nullFlag;
}
char[][] args;
int getInt (int i) {
return toInt (args[i+1]);
}
char[] getString (int i) {
return args[i+1];
}
double getDouble (int i) {
return toDouble(args[i+1]);
}
// This works
T getRowElement(T) (uint i) {
static if (is (T == int)) {
return getInt (i);
} else static if (is (T == char[])) {
return getString (i);
} else static if (is (T == double)) {
return getDouble (i);
} else {
static assert (0);
}
}
// So do these when the index is uint. If you use void getElem (int i, .....
// then it fails as it does not know how to differentiate between "int value"
// and "double value" signatures.
void getElem (uint i, ref int value) {
value = getInt (i);
}
void getElem (uint i, ref char[] value) {
value = getString (i);
}
void getElem (uint i, ref double value) {
value = getDouble (i);
}
/* Simulate a typesafe fetch from the database.
*
* With thanks to Chris Nicholson-Sauls, Lutger Blijdestijn, and Christian Kam
* who provided code and information on how to make this possible.
*
* Thanks to Kirk McDonald for for the type-safe fetch idea.
*/
Row!(T) fetchone(T ...) () {
Row!(T) r;
foreach (i, val; r.t) {
r.t[i] = getRowElement!(typeof(r.t[i]))(i);
// Works too
//getElem (i, r.t[i]);
}
static if (T.length == 6) {
//~ r.t[0] = "Myron";
//~ r.t[1] = 10;
//~ r.t[2] = "addr1";
//~ r.t[3] = "addr2";
//~ r.t[4] = "addr3";
//~ r.t[5] = 100001.10;
r.nullFlag[0] = true;
r.nullFlag[1] = false;
r.nullFlag[2] = false;
r.nullFlag[3] = true;
r.nullFlag[4] = false;
r.nullFlag[5] = false;
}
static if (T.length == 3) {
//~ r.t [0] = 34;
//~ r.t [1] = r"c:\dir1\dir2\dir2\";
//~ r.t [2] = "filename";
r.nullFlag[0] = false;
r.nullFlag[1] = true;
r.nullFlag[2] = false;
}
return r;
}
/* Fetch a typesafe record from the database and populate the struct.
*
* With thanks to Chris Nicholson-Sauls, Lutger Blijdestijn, and Christian Kam.
*/
T fetchstruc(T) () {
static if (is (T == struct)) {
auto r = fetchone!(FieldTypeTuple!(T))();
T t;
foreach (i, v; r.t) {
// According to Christian, using v may not work every time.
t.tupleof[i] = r.t[i];
}
return t;
} else {
static assert (0);
}
}
/* Fetch a typesafe record from the database, populate the struct and set
* null field flags.
*/
T fetchnullstruc(T) () {
static if (is (T == struct)) {
auto r = fetchone!(FieldTypeTuple!(T)[0..length-1])();
T t;
foreach (i, v; r.t) {
// According to Christian, using v may not work every time.
t.tupleof[i] = r.t[i];
}
foreach (i, nullFlagValue; r.nullFlag) {
t.nullFlag[i] = nullFlagValue;
}
return t;
} else {
static assert (0);
}
}
void main (char[][] args) {
.args = args;
auto x = fetchstruc!(ValueStruc) ();
x.addr3, x.balance);
auto y = fetchstruc!(OtherValue) ();
writefln ("%s, %s, %s", y.type, y.dirname, y.filename);
auto a = fetchnullstruc!(ValueStrucWNull) ();
a.addr3, a.balance, a.nullFlag);
auto b = fetchnullstruc!(OtherValueWNull) ();
writefln ("%s, %s, %s, %s", b.type, b.dirname, b.filename, b.nullFlag);
}
Jun 11 2007
Lutger wrote:Myron Alexander wrote:Thanks Lutger. One down, one to go. Regards, Myron. P.S. Here is an example using 2 structs:You can use foreach on tuples: foreach(index, value; r.t) t.tupleof[index] = value;/+ Won't compile: for (int i = 0; i < T.tupleof.length; i++) { t.tupleof[i] = r.t[i]; } +/import std.stdio; import std.traits; /* Example value object. */ struct ValueStruc { char[] name; int age; char[] addr1; char[] addr2; char[] addr3; double balance; } struct OtherValue { int type; char[] dirname; char[] filename; } struct ValueStrucWNull { char[] name; int age; char[] addr1; char[] addr2; char[] addr3; double balance; bool[6] nullFlag; } struct OtherValueWNull { int type; char[] dirname; char[] filename; bool[3] nullFlag; } /* Typesafe database row object. */ struct Row(T ...) { T t; bool[T.length] nullFlag; } /* Simulate a typesafe fetch from the database. */ Row!(T) fetchone(T ...) () { Row!(T) r; /+ --- Won't compile -------------------------------------------------- int i = 0; r.t[i++] = "Myron"; r.t[i++] = 10; r.t[i++] = "addr1"; r.t[i++] = "addr2"; r.t[i++] = "addr3"; r.t[i++] = 100001.10; ----------------------------------------------------------------------- +/ static if (T.length == 6) { r.t[0] = "Myron"; r.t[1] = 10; r.t[2] = "addr1"; r.t[3] = "addr2"; r.t[4] = "addr3"; r.t[5] = 100001.10; r.nullFlag[0] = true; r.nullFlag[1] = false; r.nullFlag[2] = false; r.nullFlag[3] = true; r.nullFlag[4] = false; r.nullFlag[5] = false; } static if (T.length == 3) { r.t [0] = 34; r.t [1] = r"c:\dir1\dir2\dir2\"; r.t [2] = "filename"; r.nullFlag[0] = false; r.nullFlag[1] = true; r.nullFlag[2] = false; } return r; } /* Fetch a typesafe record from the database and populate the struct. */ T fetchstruc(T) () { static if (is (T == struct)) { auto r = fetchone!(FieldTypeTuple!(T))(); T t; foreach (i, v; r.t) { t.tupleof[i] = v; } return t; } else { static assert (0); } } /* Fetch a typesafe record from the database, populate the struct and set * null field flags. */ T fetchnullstruc(T) () { static if (is (T == struct)) { auto r = fetchone!(FieldTypeTuple!(T)[0..length-1])(); T t; foreach (i, v; r.t) { t.tupleof[i] = v; } foreach (i, nullFlagValue; r.nullFlag) { t.nullFlag[i] = nullFlagValue; } return t; } else { static assert (0); } } void main () { auto x = fetchstruc!(ValueStruc) (); x.addr3, x.balance); auto y = fetchstruc!(OtherValue) (); writefln ("%s, %s, %s", y.type, y.dirname, y.filename); auto a = fetchnullstruc!(ValueStrucWNull) (); a.addr3, a.balance, a.nullFlag); auto b = fetchnullstruc!(OtherValueWNull) (); writefln ("%s, %s, %s, %s", b.type, b.dirname, b.filename, b.nullFlag); }
Jun 11 2007
Hi Myron,
I am also thinking about this problem for quit a while.
Maybe you can use the D Mixin feature and compile time manipulation of
strings to create an database-table adequate structure :
template GenStruct(char[] Name, char[] M1)
{
const char[] GenStruct = "struct " ~ Name ~ "{ int " ~ M1 ~ "; }";
}
mixin(GenStruct!("Foo", "bar"));
Just an idea, Bjoern
Myron Alexander schrieb:
Hello.
Is it possible to populate a struct using RTTI?
Example:
Say I have a struct as such:
struct Example {
int x;
int y;
char[] z;
}
and I want to create and populate the structure from a function:
T populate(T) () {
T t;
t.field[0] = 1;
t.field[1] = 2;
t.field[2] = "testing";
return t;
}
void main() {
auto x = populate!(Example)();
}
Is this possible? If so, what is the syntax?
Thanks ahead,
Myron.
Jun 11 2007
Hi Myron, I think my previous suggestion will not work; (compiletime issue)
However, I guess your question is regarding the database row[][]
problem, or how to create an adequate datatype for an database-table at
compile time.
I would like to suggest to have a look on this solution (runtime)
pseudo code first :
program startup
connecttodb
def tablerow as Arraylist
// browse system tables
foreach table in db
addTableInformation // name f.i.
foreach tablerow in table
// create an object which is adequate to the row datatyp
// to do this use the /factory pattern/, see link below
// next transfer rowinformation into this object
add this object to tablerow
end
end
So now you have a chained list of objects, where each object represents
one table-row (or table-field, if you like)
In D I would choose an associative array containing the tablename as
index and the Arraylist as value;
factory pattern link :
http://www.dofactory.com/Patterns/PatternAbstract.aspx
probabaly you prefer the prototyp pattern; You will find information
regarding this pattern on the same site.
Regarding the Arraylist, Tango has to offer a lot of collection classes,
I guess ArraySeq is what you need, but I am not sure, so you have to ask
Sean.
your row class can look like this
class row
private:
string rowname
string rowtype
boolean primeryKey
....
end
your concrete row class may be
class varcharRow inherits row
// alias varchar char[]
private:
varchar value // the row value
...
end
// So if your database-table-row type is varchar, we will add an
//instance of varcharRow to Arraylist.
Just a quick hack but hopefully I was able to figure out the idea; Some
feedback would be nice;
Bjoern
Myron Alexander schrieb:
Hello.
Is it possible to populate a struct using RTTI?
Example:
Say I have a struct as such:
struct Example {
int x;
int y;
char[] z;
}
and I want to create and populate the structure from a function:
T populate(T) () {
T t;
t.field[0] = 1;
t.field[1] = 2;
t.field[2] = "testing";
return t;
}
void main() {
auto x = populate!(Example)();
}
Is this possible? If so, what is the syntax?
Thanks ahead,
Myron.
Jun 11 2007
BLS wrote:Hi Myron, I think my previous suggestion will not work; (compiletime issue)Hello Bjoern. Thanks for the suggestion. I am hoping to build what I call a type-safe fetch mechanism so constructing the template at compile time is not a problem. For an example of what I am hoping to achieve, take a look at my response to Chris. If I can get that right, I will be extremely happy. I currently have a "generic" mechanism using Box arrays and I am trying to keep my implementation as "simple" as possible so the use of DAO type factories does not fit into the theme. All the best, Myron.
Jun 11 2007









Myron Alexander <someone somewhere.com> 