digitalmars.D - Mixin Expressions, can't evalutate string variable
- Andrej Mitrovic (19/19) Aug 05 2010 I think this should work:
- Tomek =?UTF-8?B?U293acWEc2tp?= (8/38) Aug 05 2010 template GenStruct(string Name, string M1)
- Tomek =?UTF-8?B?U293acWEc2tp?= (7/49) Aug 05 2010 To avoid the WTF you may find CTFE useful (and easier on the eye):
- Andrej Mitrovic (14/57) Aug 05 2010 Hmm.. ok. Adding immutable helps. I'm still a bit confused tho,
- Tomek =?UTF-8?B?U293acWEc2tp?= (7/24) Aug 05 2010 And good.
- Steven Schveighoffer (22/30) Aug 05 2010 Before you respond with more WTF, there is a subtlety here :)
- Andrej Mitrovic (42/75) Aug 05 2010 Thanks, Steven!
- Philippe Sigaud (22/45) Aug 05 2010 You can get the name of an alias using __traits(identifier, aliasName), ...
- Andrej Mitrovic (10/65) Aug 05 2010 I was using mangledName!() from std.straits. __traits works prefectly,
- Jacob Carlborg (4/64) Aug 06 2010 --
- Andrej Mitrovic (3/109) Aug 06 2010 I've already tried that. But .mangleof on an aliased symbol just returns
- Jonathan M Davis (3/5) Aug 06 2010 That sounds like a bug report in the making.
- Philippe Sigaud (14/18) Aug 06 2010 There, found it again, while answering another thread:
- Andrej Mitrovic (15/34) Aug 06 2010 Slightly OT: I've noticed you're often missing the word "know" in your p...
- Andrej Mitrovic (6/11) Aug 06 2010 No I was wrong, it won't allow me to use .mangleof on an alias of a func...
- Andrej Mitrovic (30/44) Aug 06 2010 Actually I better report this, it might lead to unexpected behavior
- Andrej Mitrovic (10/58) Aug 06 2010 Damn regexe(s|n).
- Andrej Mitrovic (13/77) Aug 07 2010 You know, I just had an idea. It would be really cool to have some sort ...
- Nick Sabalausky (17/32) Aug 07 2010 Probably not quite as fancy as what you're talking about, but my SemiTwi...
- Andrej Mitrovic (2/40) Aug 07 2010
- Andrej Mitrovic (83/135) Aug 07 2010 Anyway, I've updated autoCall(), so now you can pass arguments like usua...
- Philippe Sigaud (9/15) Aug 05 2010 Oh, oh, lots of shiny new things in std.traits!
- Andrej Mitrovic (77/97) Aug 05 2010 Hope you have fun with it!
- Nick Sabalausky (21/34) Aug 05 2010 The key is that the argument to mixin() must be known at compile-time. W...
I think this should work: string s = "int x;"; mixin(s); void main() { } But I get: testtest.d(11): Error: argument to mixin must be a string, not (s) I get a similar error with the template example from the docs: template GenStruct(string Name, string M1) { string GenStruct = "struct " ~ Name ~ "{ int " ~ M1 ~ "; }"; } mixin(GenStruct!("Foo", "bar")); void main() { } testtest.d(27): Error: argument to mixin must be a string, not (GenStruct) This is really weird, I swear it worked for me a couple of days ago. :s Maybe I accidentally modified a library file, so I'll have a look. Meanwhile can someone succesfully compile these?
Aug 05 2010
Andrej Mitrovic napisał:I think this should work: string s = "int x;"; mixin(s); void main() { } But I get: testtest.d(11): Error: argument to mixin must be a string, not (s) I get a similar error with the template example from the docs: template GenStruct(string Name, string M1) { string GenStruct = "struct " ~ Name ~ "{ int " ~ M1 ~ "; }"; } mixin(GenStruct!("Foo", "bar")); void main() { } testtest.d(27): Error: argument to mixin must be a string, not (GenStruct) This is really weird, I swear it worked for me a couple of days ago. :s Maybe I accidentally modified a library file, so I'll have a look. Meanwhile can someone succesfully compile these?template GenStruct(string Name, string M1) { immutable string GenStruct = "struct " ~ Name ~ "{ int " ~ M1 ~ "; }"; } It must be immutable to be seen as a template expression. Otherwise it's one mutable string declaration that happens to be named same as the enclosing template. Tomek
Aug 05 2010
Tomek Sowiński napisał:Andrej Mitrovic napisał:To avoid the WTF you may find CTFE useful (and easier on the eye): string GenStruct(string Name, string M1) { return "struct " ~ Name ~ "{ int " ~ M1 ~ "; }"; } mixin(GenStruct("Foo", "bar")); TomekI think this should work: string s = "int x;"; mixin(s); void main() { } But I get: testtest.d(11): Error: argument to mixin must be a string, not (s) I get a similar error with the template example from the docs: template GenStruct(string Name, string M1) { string GenStruct = "struct " ~ Name ~ "{ int " ~ M1 ~ "; }"; } mixin(GenStruct!("Foo", "bar")); void main() { } testtest.d(27): Error: argument to mixin must be a string, not (GenStruct) This is really weird, I swear it worked for me a couple of days ago. :s Maybe I accidentally modified a library file, so I'll have a look. Meanwhile can someone succesfully compile these?template GenStruct(string Name, string M1) { immutable string GenStruct = "struct " ~ Name ~ "{ int " ~ M1 ~ "; }"; } It must be immutable to be seen as a template expression. Otherwise it's one mutable string declaration that happens to be named same as the enclosing template.
Aug 05 2010
Hmm.. ok. Adding immutable helps. I'm still a bit confused tho, because this will not compile: string input2 = "int y;"; mixin(input2); But this will compile: immutable string input2 = "int y;"; mixin(input2); And this too will compile: string returnString(string input) { return input; } mixin(returnString("int y;")); Tomek Sowiński Wrote:Andrej Mitrovic napisał:I think this should work: string s = "int x;"; mixin(s); void main() { } But I get: testtest.d(11): Error: argument to mixin must be a string, not (s) I get a similar error with the template example from the docs: template GenStruct(string Name, string M1) { string GenStruct = "struct " ~ Name ~ "{ int " ~ M1 ~ "; }"; } mixin(GenStruct!("Foo", "bar")); void main() { } testtest.d(27): Error: argument to mixin must be a string, not (GenStruct) This is really weird, I swear it worked for me a couple of days ago. :s Maybe I accidentally modified a library file, so I'll have a look. Meanwhile can someone succesfully compile these?template GenStruct(string Name, string M1) { immutable string GenStruct = "struct " ~ Name ~ "{ int " ~ M1 ~ "; }"; } It must be immutable to be seen as a template expression. Otherwise it's one mutable string declaration that happens to be named same as the enclosing template. Tomek
Aug 05 2010
Andrej Mitrovic napisał:Hmm.. ok. Adding immutable helps. I'm still a bit confused tho, because this will not compile: string input2 = "int y;"; mixin(input2);input2 is mutable, so theoretically there's no telling what value it holds.But this will compile: immutable string input2 = "int y;"; mixin(input2);And good.And this too will compile: string returnString(string input) { return input; } mixin(returnString("int y;"));Because the function is *nice*, compiler can evaluate the call at compile-time (see my other post). Somewhere on the D page (Lang. Ref. > Functions ?) there's a largish explanation what's *nice*. Tomek
Aug 05 2010
On Thu, 05 Aug 2010 15:34:44 -0400, Tomek Sowiński <just ask.me> wrote:Andrej Mitrovic napisał:Before you respond with more WTF, there is a subtlety here :) A string is aliased to immutable(char)[]. This means that the *data* pointed at is immutable but the *array* is mutable. You can reassign a string to point at some other immutable data, or change the length of the array. To illustrate this: string input2 = "int y;"; static this() { input2 = "int x;"; // perfectly legal } mixin(input2); // what does this do? Now, immutable string means: immutable(immutable(char)[]), which reduces to immutable(char[]), meaning both the data pointed at *and* the array are immutable (note the distinction of where the parentheses are). This can be used in CTFE and mixins because the compiler knows the value is completely defined at compile-time. strings (the kind where the array part is mutable) can be used as mixins as long as they are rvalues, such as the returns from functions which are CTFE capable. -SteveHmm.. ok. Adding immutable helps. I'm still a bit confused tho, because this will not compile: string input2 = "int y;"; mixin(input2);input2 is mutable, so theoretically there's no telling what value it holds.
Aug 05 2010
Thanks, Steven! You don't want to know what I'm up to :p. I'm using some traits to find out what kind of parameters a function takes. I'm also using a demangler from phobos to find out the name of the function (But I can't find any straightforward way to get a name of a function without getting back "1D_5std_5funcName" etc, so I just take a hardcoded slice). Anyway, I have a template function which takes as it's parameters a functio= n (aliased to func), and some arguments (right now just one in my hardcoded code). It then creates a string which can be compiled via the mixin. It constructs the string by checking the parameter types of func, and for any ref or out parameter it detects it appends something like this to a string: "long var1; long var2; long var3; ". For any non-out/ref parameters it constructs another string which will call that func (here is where I'm using the demangler to get the real name of th= e function). So the other string would eventually look like so: "funcName(argN.., var1, var2, var3); It then concatenates both strings and returns it, creating the whole shebang: "int var1; double var2; funcName(argN..., var1, var2, var3);" This can then be used with mixin() at the calling site. I was inspiried to try this out when bearophile wanted some new tuple syntax assignment in D. So anyway, at the calling site I have this: mixin(unpack!(getTimes)(r"C:\\cookies")); getTimes() is a Phobos function with the signature: getTimes(in char[] name, out d_time ftc, out d_time fta, out d_time ftm) And now I automatically have var1, var2, and var3 at my disposal. It was just an exercise for fun but it's cool that things like this are possible in D. It would be nice if I could get the actual names of the parameters the function takes + the clear name of the function itself, that way I'd actually get back variables "ftc, fta, ftm" back). Right now the code is a big mess but I could fix it up a lot and post it here if anyone cares. On Thu, Aug 5, 2010 at 9:48 PM, Steven Schveighoffer <schveiguy yahoo.com>w= rote:On Thu, 05 Aug 2010 15:34:44 -0400, Tomek Sowi=C5=84ski <just ask.me> wro=te:Andrej Mitrovic napisa=C5=82:ionHmm.. ok. Adding immutable helps. I'm still a bit confused tho,Before you respond with more WTF, there is a subtlety here :) A string is aliased to immutable(char)[]. This means that the *data* pointed at is immutable but the *array* is mutable. You can reassign a string to point at some other immutable data, or change the length of the array. To illustrate this: string input2 =3D "int y;"; static this() { input2 =3D "int x;"; // perfectly legal } mixin(input2); // what does this do? Now, immutable string means: immutable(immutable(char)[]), which reduces to immutable(char[]), meaning both the data pointed at *and* the array are immutable (note the distinct=because this will not compile: string input2 =3D "int y;"; mixin(input2);input2 is mutable, so theoretically there's no telling what value it holds.of where the parentheses are). This can be used in CTFE and mixins becau=sethe compiler knows the value is completely defined at compile-time. strings (the kind where the array part is mutable) can be used as mixins =aslong as they are rvalues, such as the returns from functions which are CT=FEcapable. -Steve
Aug 05 2010
On Thu, Aug 5, 2010 at 22:24, Andrej Mitrovic <andrej.mitrovich gmail.com>wrote:Thanks, Steven! You don't want to know what I'm up to :p.Yes, yes, wo do!I'm using some traits to find out what kind of parameters a function takes. I'm also using a demangler from phobos to find out the name of the function (But I can't find any straightforward way to get a name of a function without getting back "1D_5std_5funcName" etc, so I just take a hardcoded slice).You can get the name of an alias using __traits(identifier, aliasName), like this for example: template Name(alias a) { enum string Name = __traits(identifier, a); } int foo(int i) { return 0;} import std.stdio; void main() { writeln(Name!foo); // "foo", not "a". } As for demangling, how do you do to get mangled names in the first place?Anyway, I have a template function which takes as it's parameters a function (aliased to func), and some arguments (right now just one in my hardcoded code). It then creates a string which can be compiled via the mixin. It constructs the string by checking the parameter types of func, and for any ref or out parameter it detects it appends something like this to a string: "long var1; long var2; long var3; ".How can you know if a parameter is ref or out? I remember seeing something about it in Phobos svn, are you using it?So anyway, at the calling site I have this: mixin(unpack!(getTimes)(r"C:\\cookies")); getTimes() is a Phobos function with the signature: getTimes(in char[] name, out d_time ftc, out d_time fta, out d_time ftm) And now I automatically have var1, var2, and var3 at my disposal.That's fun :)It was just an exercise for fun but it's cool that things like this are possible in D. It would be nice if I could get the actual names of the parameters the function takes + the clear name of the function itself, that way I'd actually get back variables "ftc, fta, ftm" back)I'm pretty sure I saw some code to do this. But maybe that was a D1 thing, using mangled names, too. in dsource/scrapple? Philippe
Aug 05 2010
On Thu, Aug 5, 2010 at 11:29 PM, Philippe Sigaud <philippe.sigaud gmail.com>wrote:On Thu, Aug 5, 2010 at 22:24, Andrej Mitrovic <andrej.mitrovich gmail.com>wrote:I was using mangledName!() from std.straits. __traits works prefectly, Thanks!Thanks, Steven! You don't want to know what I'm up to :p.Yes, yes, wo do!I'm using some traits to find out what kind of parameters a function takes. I'm also using a demangler from phobos to find out the name of the function (But I can't find any straightforward way to get a name of a function without getting back "1D_5std_5funcName" etc, so I just take a hardcoded slice).You can get the name of an alias using __traits(identifier, aliasName), like this for example: template Name(alias a) { enum string Name = __traits(identifier, a); } int foo(int i) { return 0;} import std.stdio; void main() { writeln(Name!foo); // "foo", not "a". } As for demangling, how do you do to get mangled names in the first place?Not svn, it's in 2.047 (maybe in earlier ones as well) in std.traits: ParameterTypeTuple!(alias) - for the types ParameterStorageClassTuple!(alias) - for the storage classAnyway, I have a template function which takes as it's parameters a function (aliased to func), and some arguments (right now just one in my hardcoded code). It then creates a string which can be compiled via the mixin. It constructs the string by checking the parameter types of func, and for any ref or out parameter it detects it appends something like this to a string: "long var1; long var2; long var3; ".How can you know if a parameter is ref or out? I remember seeing something about it in Phobos svn, are you using it?Dunno, I haven't been using D1 really (actually I tried it some years ago with Tango but it left me wanting more so I never stuck around much). But D2 is super-fun.So anyway, at the calling site I have this: mixin(unpack!(getTimes)(r"C:\\cookies")); getTimes() is a Phobos function with the signature: getTimes(in char[] name, out d_time ftc, out d_time fta, out d_time ftm) And now I automatically have var1, var2, and var3 at my disposal.That's fun :)It was just an exercise for fun but it's cool that things like this are possible in D. It would be nice if I could get the actual names of the parameters the function takes + the clear name of the function itself, that way I'd actually get back variables "ftc, fta, ftm" back)I'm pretty sure I saw some code to do this. But maybe that was a D1 thing, using mangled names, too. in dsource/scrapple? Philippe
Aug 05 2010
On 2010-08-05 23:50, Andrej Mitrovic wrote:On Thu, Aug 5, 2010 at 11:29 PM, Philippe Sigaud <philippe.sigaud gmail.com <mailto:philippe.sigaud gmail.com>> wrote: On Thu, Aug 5, 2010 at 22:24, Andrej Mitrovic <andrej.mitrovich gmail.com <mailto:andrej.mitrovich gmail.com>> wrote: Thanks, Steven! You don't want to know what I'm up to :p. Yes, yes, wo do! I'm using some traits to find out what kind of parameters a function takes. I'm also using a demangler from phobos to find out the name of the function (But I can't find any straightforward way to get a name of a function without getting back "1D_5std_5funcName" etc, so I just take a hardcoded slice). You can get the name of an alias using __traits(identifier, aliasName), like this for example: template Name(alias a) { enum string Name = __traits(identifier, a); } int foo(int i) { return 0;} import std.stdio; void main() { writeln(Name!foo); // "foo", not "a". } As for demangling, how do you do to get mangled names in the first place? I was using mangledName!() from std.straits. __traits works prefectly, Thanks!You know there is a .mangleof property for all symbols.Anyway, I have a template function which takes as it's parameters a function (aliased to func), and some arguments (right now just one in my hardcoded code). It then creates a string which can be compiled via the mixin. It constructs the string by checking the parameter types of func, and for any ref or out parameter it detects it appends something like this to a string: "long var1; long var2; long var3; ". How can you know if a parameter is ref or out? I remember seeing something about it in Phobos svn, are you using it? Not svn, it's in 2.047 (maybe in earlier ones as well) in std.traits: ParameterTypeTuple!(alias) - for the types ParameterStorageClassTuple!(alias) - for the storage class So anyway, at the calling site I have this: mixin(unpack!(getTimes)(r"C:\\cookies")); getTimes() is a Phobos function with the signature: getTimes(in char[] name, out d_time ftc, out d_time fta, out d_time ftm) And now I automatically have var1, var2, and var3 at my disposal. That's fun :) It was just an exercise for fun but it's cool that things like this are possible in D. It would be nice if I could get the actual names of the parameters the function takes + the clear name of the function itself, that way I'd actually get back variables "ftc, fta, ftm" back) I'm pretty sure I saw some code to do this. But maybe that was a D1 thing, using mangled names, too. in dsource/scrapple? Philippe Dunno, I haven't been using D1 really (actually I tried it some years ago with Tango but it left me wanting more so I never stuck around much). But D2 is super-fun.-- /Jacob Carlborg
Aug 06 2010
I've already tried that. But .mangleof on an aliased symbol just returns "alias" as a string. On Fri, Aug 6, 2010 at 10:44 AM, Jacob Carlborg <doob me.com> wrote:On 2010-08-05 23:50, Andrej Mitrovic wrote:On Thu, Aug 5, 2010 at 11:29 PM, Philippe Sigaud <philippe.sigaud gmail.com <mailto:philippe.sigaud gmail.com>> wrote: On Thu, Aug 5, 2010 at 22:24, Andrej Mitrovic <andrej.mitrovich gmail.com <mailto:andrej.mitrovich gmail.com>> wrote: Thanks, Steven! You don't want to know what I'm up to :p. Yes, yes, wo do! I'm using some traits to find out what kind of parameters a function takes. I'm also using a demangler from phobos to find out the name of the function (But I can't find any straightforward way to get a name of a function without getting back "1D_5std_5funcName" etc, so I just take a hardcoded slice). You can get the name of an alias using __traits(identifier, aliasName), like this for example: template Name(alias a) { enum string Name = __traits(identifier, a); } int foo(int i) { return 0;} import std.stdio; void main() { writeln(Name!foo); // "foo", not "a". } As for demangling, how do you do to get mangled names in the first place? I was using mangledName!() from std.straits. __traits works prefectly, Thanks!You know there is a .mangleof property for all symbols. Anyway, I have a template function which takes as it'sparameters a function (aliased to func), and some arguments (right now just one in my hardcoded code). It then creates a string which can be compiled via the mixin. It constructs the string by checking the parameter types of func, and for any ref or out parameter it detects it appends something like this to a string: "long var1; long var2; long var3; ". How can you know if a parameter is ref or out? I remember seeing something about it in Phobos svn, are you using it? Not svn, it's in 2.047 (maybe in earlier ones as well) in std.traits: ParameterTypeTuple!(alias) - for the types ParameterStorageClassTuple!(alias) - for the storage class So anyway, at the calling site I have this: mixin(unpack!(getTimes)(r"C:\\cookies")); getTimes() is a Phobos function with the signature: getTimes(in char[] name, out d_time ftc, out d_time fta, out d_time ftm) And now I automatically have var1, var2, and var3 at my disposal. That's fun :) It was just an exercise for fun but it's cool that things like this are possible in D. It would be nice if I could get the actual names of the parameters the function takes + the clear name of the function itself, that way I'd actually get back variables "ftc, fta, ftm" back) I'm pretty sure I saw some code to do this. But maybe that was a D1 thing, using mangled names, too. in dsource/scrapple? Philippe Dunno, I haven't been using D1 really (actually I tried it some years ago with Tango but it left me wanting more so I never stuck around much). But D2 is super-fun.-- /Jacob Carlborg
Aug 06 2010
On Friday, August 06, 2010 08:08:03 Andrej Mitrovic wrote:I've already tried that. But .mangleof on an aliased symbol just returns "alias" as a string.That sounds like a bug report in the making. - Jonathan M Davis
Aug 06 2010
Andrej:It was just an exercise for fun but it's cool that things like this are possible in D. It would be nice if I could get the actual names of the parameters the function takes + the clear name of the function itself, that way I'd actually get back variables "ftc, fta, ftm" back)There, found it again, while answering another thread: int foo(int i, double d) { return 0;} writeln(typeof(&foo).stringof); // "int function(int i, double d)" <-- Look Ma, arguments names! But it's a quirk of .stringof, I'm not sure it's a good idea to rely on it too much. from there, using compile-time search in a string, you can extract the arguments (those are between ( and ) ) -> "int i, double d" and from there, extracting i and d. I don't what will happen for overloaded functions, methods names, constructors, ... Philippe
Aug 06 2010
Slightly OT: I've noticed you're often missing the word "know" in your posts (e.g. "I don't what", that should be "I don't know what"). Is something filtering your posts? :) And yeah, I've noticed your other thread with the argument names. With a little bit of regex I could easily extract the variable names. I think this template could be useful in cases when you just want to try out a function which happens to writes some state in the parameters that are passed to it (out/ref params), without having to inspect the function signature and declare the proper variable types. Unfortunately there's no way to pass auto variables as parameters, but that's more of a Python territory, I guess. On the other hand, the template introduces new identifiers silently into the calling site (you can't see it in the code), so it's not all that practical I guess, not to mention a little dangerous. :p On Fri, Aug 6, 2010 at 10:22 PM, Philippe Sigaud <philippe.sigaud gmail.com>wrote:Andrej:It was just an exercise for fun but it's cool that things like this are possible in D. It would be nice if I could get the actual names of the parameters the function takes + the clear name of the function itself, that way I'd actually get back variables "ftc, fta, ftm" back)There, found it again, while answering another thread: int foo(int i, double d) { return 0;} writeln(typeof(&foo).stringof); // "int function(int i, double d)" <-- Look Ma, arguments names! But it's a quirk of .stringof, I'm not sure it's a good idea to rely on it too much. from there, using compile-time search in a string, you can extract the arguments (those are between ( and ) ) -> "int i, double d" and from there, extracting i and d. I don't what will happen for overloaded functions, methods names, constructors, ... Philippe
Aug 06 2010
On Fri, Aug 6, 2010 at 8:40 PM, Jonathan M Davis <jmdavisprog gmail.com>wrote:On Friday, August 06, 2010 08:08:03 Andrej Mitrovic wrote:No I was wrong, it won't allow me to use .mangleof on an alias of a function inside a template because that automatically calls the function (and that means I have to pass valid arguments to it). The mangledName!() template works just fine though. But I don't need mangled names, I was only using it as a workaround.I've already tried that. But .mangleof on an aliased symbol just returns "alias" as a string.That sounds like a bug report in the making. - Jonathan M Davis
Aug 06 2010
Actually I better report this, it might lead to unexpected behavior otherwise. See, this will compile: import std.stdio; auto template_func(alias func, T...)(T args) { return func.mangleof; } void test() {} unittest { writeln(template_func!(test, int)(1)); } void main() { } And this won't: import std.stdio; auto template_func(alias func, T...)(T args) { return func.mangleof; } void test(int x) {} unittest { writeln(template_func!(test, int)(1)); } void main() { } (I've added a parameter to test()). The problem is the first code actually called func, and succeeded silently since it takes no parameters. I don't think this is an expected behavior? On Sat, Aug 7, 2010 at 3:10 AM, Andrej Mitrovic <andrej.mitrovich gmail.com>wrote:On Fri, Aug 6, 2010 at 8:40 PM, Jonathan M Davis <jmdavisprog gmail.com>wrote:On Friday, August 06, 2010 08:08:03 Andrej Mitrovic wrote:No I was wrong, it won't allow me to use .mangleof on an alias of a function inside a template because that automatically calls the function (and that means I have to pass valid arguments to it). The mangledName!() template works just fine though. But I don't need mangled names, I was only using it as a workaround.I've already tried that. But .mangleof on an aliased symbol just returns "alias" as a string.That sounds like a bug report in the making. - Jonathan M Davis
Aug 06 2010
Damn regexe(s|n). I almost never need them, but when I do, I have to spend an hour trying to remember the syntax (+ I'm really used to doing regexes in Python and then there's the whole "regex objects in lang x work different than in lang y" thing). But I digress.. I think a better way is to pass strings which will be used to name the variables to be constructed and initialized (+ return an error when there's too few). And then at least you'll know there are some new local variables at your disposal by looking at the call. That way we solve both problems. On Sat, Aug 7, 2010 at 12:12 AM, Andrej Mitrovic <andrej.mitrovich gmail.comwrote:Slightly OT: I've noticed you're often missing the word "know" in your posts (e.g. "I don't what", that should be "I don't know what"). Is something filtering your posts? :) And yeah, I've noticed your other thread with the argument names. With a little bit of regex I could easily extract the variable names. I think this template could be useful in cases when you just want to try out a function which happens to writes some state in the parameters that are passed to it (out/ref params), without having to inspect the function signature and declare the proper variable types. Unfortunately there's no way to pass auto variables as parameters, but that's more of a Python territory, I guess. On the other hand, the template introduces new identifiers silently into the calling site (you can't see it in the code), so it's not all that practical I guess, not to mention a little dangerous. :p On Fri, Aug 6, 2010 at 10:22 PM, Philippe Sigaud < philippe.sigaud gmail.com> wrote:Andrej:It was just an exercise for fun but it's cool that things like this are possible in D. It would be nice if I could get the actual names of the parameters the function takes + the clear name of the function itself, that way I'd actually get back variables "ftc, fta, ftm" back)There, found it again, while answering another thread: int foo(int i, double d) { return 0;} writeln(typeof(&foo).stringof); // "int function(int i, double d)" <-- Look Ma, arguments names! But it's a quirk of .stringof, I'm not sure it's a good idea to rely on it too much. from there, using compile-time search in a string, you can extract the arguments (those are between ( and ) ) -> "int i, double d" and from there, extracting i and d. I don't what will happen for overloaded functions, methods names, constructors, ... Philippe
Aug 06 2010
You know, I just had an idea. It would be really cool to have some sort of generalized template function which can test other functions in various ways. You could pass strings as options, where you might choose the type of testing being done, such as verification tests or performance tests.. Or if a function is designed to write a file on disk, maybe you'd want to have an option for the maximum number of tests to run on that function (you don't want to be left with 10000 files written in some temp directory somewhere..), or a test to see if a function will fail with invalid input, etc. Well it's just an idea, I better take a look at the existing test frameworks and see how it's done there. On Sat, Aug 7, 2010 at 4:04 AM, Andrej Mitrovic <andrej.mitrovich gmail.com>wrote:Damn regexe(s|n). I almost never need them, but when I do, I have to spend an hour trying to remember the syntax (+ I'm really used to doing regexes in Python and then there's the whole "regex objects in lang x work different than in lang y" thing). But I digress.. I think a better way is to pass strings which will be used to name the variables to be constructed and initialized (+ return an error when there's too few). And then at least you'll know there are some new local variables at your disposal by looking at the call. That way we solve both problems. On Sat, Aug 7, 2010 at 12:12 AM, Andrej Mitrovic < andrej.mitrovich gmail.com> wrote:Slightly OT: I've noticed you're often missing the word "know" in your posts (e.g. "I don't what", that should be "I don't know what"). Is something filtering your posts? :) And yeah, I've noticed your other thread with the argument names. With a little bit of regex I could easily extract the variable names. I think this template could be useful in cases when you just want to try out a function which happens to writes some state in the parameters that are passed to it (out/ref params), without having to inspect the function signature and declare the proper variable types. Unfortunately there's no way to pass auto variables as parameters, but that's more of a Python territory, I guess. On the other hand, the template introduces new identifiers silently into the calling site (you can't see it in the code), so it's not all that practical I guess, not to mention a little dangerous. :p On Fri, Aug 6, 2010 at 10:22 PM, Philippe Sigaud < philippe.sigaud gmail.com> wrote:Andrej:It was just an exercise for fun but it's cool that things like this are possible in D. It would be nice if I could get the actual names of the parameters the function takes + the clear name of the function itself, that way I'd actually get back variables "ftc, fta, ftm" back)There, found it again, while answering another thread: int foo(int i, double d) { return 0;} writeln(typeof(&foo).stringof); // "int function(int i, double d)" <-- Look Ma, arguments names! But it's a quirk of .stringof, I'm not sure it's a good idea to rely on it too much. from there, using compile-time search in a string, you can extract the arguments (those are between ( and ) ) -> "int i, double d" and from there, extracting i and d. I don't what will happen for overloaded functions, methods names, constructors, ... Philippe
Aug 07 2010
"Andrej Mitrovic" <andrej.mitrovich gmail.com> wrote in message news:mailman.175.1281208901.13841.digitalmars-d puremagic.com...You know, I just had an idea. It would be really cool to have some sort of generalized template function which can test other functions in various ways. You could pass strings as options, where you might choose the type of testing being done, such as verification tests or performance tests.. Or if a function is designed to write a file on disk, maybe you'd want to have an option for the maximum number of tests to run on that function (you don't want to be left with 10000 files written in some temp directory somewhere..), or a test to see if a function will fail with invalid input, etc. Well it's just an idea, I better take a look at the existing test frameworks and see how it's done there.Probably not quite as fancy as what you're talking about, but my SemiTwist D Tools library has a module that includes something that's similar to assert but: - Allows to you verify that a particular statement throws a particular type of exception. - Properly reports if an expression throws (and you didn't expect it to). - Doesn't abort the program on failure. - Reports "expected" expression and "actual" value. http://www.dsource.org/projects/semitwist/browser/trunk/src/semitwist/apps/tests/deferAssertTest/main.d http://www.dsource.org/projects/semitwist/browser/trunk/src/semitwist/util/deferAssert.d It does need some clean-up and improvements, but it at least works. (Although, trunk is currently in the process of switching from D1/Tango to D2/Phobos, so the latest revisions might be broken and it definitely doesn't take advantage of D2-specific features yet. But the version included with Goldie 0.3 does work fine on D1/Tango though).
Aug 07 2010
Cool stuff! I'll have a look later. Thanks. On Sat, Aug 7, 2010 at 9:53 PM, Nick Sabalausky <a a.a> wrote:"Andrej Mitrovic" <andrej.mitrovich gmail.com> wrote in message news:mailman.175.1281208901.13841.digitalmars-d puremagic.com...You know, I just had an idea. It would be really cool to have some sortofgeneralized template function which can test other functions in various ways. You could pass strings as options, where you might choose the type of testing being done, such as verification tests or performance tests.. Or if a function is designed to write a file on disk, maybe you'd want to have an option for the maximum number of tests to run on that function (you don't want to be left with 10000 files written in some temp directory somewhere..), or a test to see if a function will fail with invalidinput,etc. Well it's just an idea, I better take a look at the existing test frameworks and see how it's done there.Probably not quite as fancy as what you're talking about, but my SemiTwist D Tools library has a module that includes something that's similar to assert but: - Allows to you verify that a particular statement throws a particular type of exception. - Properly reports if an expression throws (and you didn't expect it to). - Doesn't abort the program on failure. - Reports "expected" expression and "actual" value. http://www.dsource.org/projects/semitwist/browser/trunk/src/semitwist/apps/tests/deferAssertTest/main.d http://www.dsource.org/projects/semitwist/browser/trunk/src/semitwist/util/deferAssert.d It does need some clean-up and improvements, but it at least works. (Although, trunk is currently in the process of switching from D1/Tango to D2/Phobos, so the latest revisions might be broken and it definitely doesn't take advantage of D2-specific features yet. But the version included with Goldie 0.3 does work fine on D1/Tango though).
Aug 07 2010
Anyway, I've updated autoCall(), so now you can pass arguments like usual but also specify the names of any ref/out variables that will be created. It will also check to make sure the number of arguments matches for the call to the function. Of course, arguments have to be evaluable at compile time (You can't just pass a string, it has to be immutable). Here's the code: import std.file; // getTimes() import std.conv; // to!string() import std.traits; // Parameter types, storage, introspection import std.stdio; // Notes: // Currently it only works with simple built-in types: // Integrals, strings, but not objects. // // It will throw a compiler error and a message if there are unmatched // number of arguments for the call to func(). // Arguments have to be evaluable at compile time. auto autoCall(alias func, T...)(T args) { alias ParameterStorageClass STC; // storage class enum alias ParameterTypeTuple!(func) paramTypes; // types of parameters alias ParameterStorageClassTuple!(func) storageTypes; // storage class of parameters static if (paramTypes.length != args.length) { pragma(msg, "autoCall: Template Error: Unmatched number of arguments for call to " ~ __traits(identifier, func) ~ "()"); static assert(0); } string declString, callString; // eg: callString = "funcName(" callString = __traits(identifier, func) ~ "("; foreach (int i, storageType; storageTypes) { if (storageType == STC.OUT || storageType == STC.REF) { // eg: declString ~= "int newParamName; " declString ~= paramTypes[i].stringof ~ " " ~ args[i] ~ "; "; // eg: callString = "funcName(" ~ "newParamName," callString ~= " " ~ args[i] ~ ","; } else { // Fetch the value of args or args[i] and expand it to callString. // We cannot use the actual names of the arguments since that would // not work with literals (unless we added tests and more branching) // need to use static if here due to array bounds checking static if (args.length == 1) { // eg: callString = "funcName(args, newParamName," callString ~= '"' ~ to!string(args) ~ '"' ~ ","; } else { // eg: callString = "funcName(args[i], newParamName," callString ~= '"' ~ to!string(args[i]) ~ '"' ~ ","; } } } // remove the extra comma and close the call string callString = callString[0 .. $ - 1] ~ ");"; // return joined strings ready to be used with mixin() return declString ~= callString; } void testMe(string x, ref int z, string y) { writeln(x, y); z = 5; } unittest { immutable string var1 = "foo"; immutable string var2 = "bar"; mixin(autoCall!(testMe)(var1, "newvar", var2)); assert(newvar == 5); } void main() { } Fun stuff, right? :p On Sat, Aug 7, 2010 at 9:57 PM, Andrej Mitrovic <andrej.mitrovich gmail.com>wrote:Cool stuff! I'll have a look later. Thanks. On Sat, Aug 7, 2010 at 9:53 PM, Nick Sabalausky <a a.a> wrote:"Andrej Mitrovic" <andrej.mitrovich gmail.com> wrote in message news:mailman.175.1281208901.13841.digitalmars-d puremagic.com...You know, I just had an idea. It would be really cool to have some sortofgeneralized template function which can test other functions in various ways. You could pass strings as options, where you might choose the type of testing being done, such as verification tests or performance tests.. Or if a function is designed to write a file on disk, maybe you'd want to have an option for the maximum number of tests to run on that function (youdon'twant to be left with 10000 files written in some temp directory somewhere..), or a test to see if a function will fail with invalidinput,etc. Well it's just an idea, I better take a look at the existing test frameworks and see how it's done there.Probably not quite as fancy as what you're talking about, but my SemiTwist D Tools library has a module that includes something that's similar to assert but: - Allows to you verify that a particular statement throws a particular type of exception. - Properly reports if an expression throws (and you didn't expect it to). - Doesn't abort the program on failure. - Reports "expected" expression and "actual" value. http://www.dsource.org/projects/semitwist/browser/trunk/src/semitwist/apps/tests/deferAssertTest/main.d http://www.dsource.org/projects/semitwist/browser/trunk/src/semitwist/util/deferAssert.d It does need some clean-up and improvements, but it at least works. (Although, trunk is currently in the process of switching from D1/Tango to D2/Phobos, so the latest revisions might be broken and it definitely doesn't take advantage of D2-specific features yet. But the version included with Goldie 0.3 does work fine on D1/Tango though).
Aug 07 2010
On Thu, Aug 5, 2010 at 23:50, Andrej Mitrovic <andrej.mitrovich gmail.com>wrote:Oh, oh, lots of shiny new things in std.traits! I didn't specifically look at this module for 2.047, my mistake. And, demange(mangledName!foo) gives back a qualified name, nice! I was looking as a way to get that, not two hours ago. *goes play with it* Ah, it doesn't work with templates names, though. Thanks Andrej! PhilippeAs for demangling, how do you do to get mangled names in the first place?I was using mangledName!() from std.straits. __traits works prefectly, Thanks!
Aug 05 2010
Hope you have fun with it! Anyway, here's a much cleaner edition of my magic little template function. There's probably a host of errors and silly mistakes, but this is just a proof of concept more than anything else, really: import std.file; // getTimes() import std.conv; // to!string() import std.traits; // Parameter types, storage, introspection import std.stdio; // Note: // Errors are messy, since the function returns an arbitrary string ready to be // mixed in. // // If there are not enough arguments in args to make the call, autoCall // will re-send the same argument value for each one missing in func's signature. // (this is by accident, not design) // // Tests could be added to make sure there are enough arguments in the // args tuple however. auto autoCall(alias func, T...)(T args) { alias ParameterStorageClass STC; // storage class enum alias ParameterTypeTuple!(func) types; // types of parameters alias ParameterStorageClassTuple!(func) params; // storage class of parameters string declString, callString; callString = __traits(identifier, func) ~ "("; // funcName( foreach (int i, param; params) { if (param == STC.OUT || param == STC.REF) { // e.g. "int var1; " declString ~= types[i].stringof ~ " var" ~ i.stringof ~ "; "; // e.g. "funcName(" ~= " var1," callString ~= " var" ~ i.stringof ~ ","; } else { // The non-out & non-ref parameter to func is already present in args, // fetch it's value and append it to the call string. // need to use static if due to DMD complaints about array bounds // in the else clause static if (args.length == 1) { // e.g. "funcName(" ~= "r'filename', " callString ~= '"' ~ to!string(args) ~ '"' ~ ","; } else { callString ~= '"' ~ to!string(args[i]) ~ '"' ~ ","; } } } // remove the remaining comma and close the call string callString = callString[0 .. $ - 1] ~ ");"; // return joined strings ready to be mixin()'ed return declString ~= callString; } void testMe(string x, string y) { writeln(x, y); } unittest { mixin(autoCall!(getTimes)(r"C:\\cookies")); mixin(autoCall!(testMe)("test")); writefln("var1: %s, var2: %s, var3: %s", var1, var2, var3); } void main() { } You'll have to replace the string in the first mixin ("cookies") to some file on your drive. I'm not sure if the Linux version of getTimes works the same way though. On Fri, Aug 6, 2010 at 12:05 AM, Philippe Sigaud <philippe.sigaud gmail.com>wrote:On Thu, Aug 5, 2010 at 23:50, Andrej Mitrovic <andrej.mitrovich gmail.com>wrote:Oh, oh, lots of shiny new things in std.traits! I didn't specifically look at this module for 2.047, my mistake. And, demange(mangledName!foo) gives back a qualified name, nice! I was looking as a way to get that, not two hours ago. *goes play with it* Ah, it doesn't work with templates names, though. Thanks Andrej! PhilippeAs for demangling, how do you do to get mangled names in the first place?I was using mangledName!() from std.straits. __traits works prefectly, Thanks!
Aug 05 2010
"Andrej Mitrovic" <andrej.mitrovich gmail.com> wrote in message news:i3f3a0$25fv$1 digitalmars.com...Hmm.. ok. Adding immutable helps. I'm still a bit confused tho,The key is that the argument to mixin() must be known at compile-time. When the compiler reaches a mixin(...), it looks at the argument to mixin and tries to evaluate it at compile-time, which may or may not be successful.because this will not compile: string input2 = "int y;"; mixin(input2);"string input2" is a run-time variable. When the compiler sees "mixin(input2)" it tries to evaluate the expression "input2" at compile-time. When it does that, it notices that input2 is mutable (ie, What if in between those two lines there was: "if(args.length > 3) input2 = someOtherString"?). Since the value can change at run-time, the compiler doesn't know at compile-time what the value will be. So it can't mix it in. True, in this particular case it could figure it out, but not in the general case, so it doesn't bother.But this will compile: immutable string input2 = "int y;"; mixin(input2);The compiler sees "mixin(input2)". It tries to evaluate the expression "input2" at compile-time. It sees that "input2" is immutable so it goes "Ah ha! That's *never* going to change, so I know exactly what the value is always going to be, so I can just plop it right in." Doing "enum input2" would also work for the same reason.And this too will compile: string returnString(string input) { return input; } mixin(returnString("int y;"));The compiler reaches the mixin and tries to evaluate "returnString("int y;")" at compile-time. Thanks to CTFE, it's able to, so this works.
Aug 05 2010