digitalmars.D - Mixin template parameters / mixin template literals
- =?UTF-8?B?Ikx1w61z?= Marques" (57/57) Apr 23 2013 Consider:
- Diggory (12/12) Apr 24 2013 One way this could be done is by expanding on lazy parameters.
- Timon Gehr (3/15) Apr 24 2013 This is a little dangerous as it looks like an ordinary expression but
- Diggory (4/26) Apr 24 2013 Surely it's no more dangerous than lazy parameters already are.
- Timon Gehr (3/26) Apr 24 2013 It surely is. 'lazy' parameters do not affect symbol lookup in the
- =?UTF-8?B?Ikx1w61z?= Marques" (14/21) Apr 24 2013 That's true, and that was one reason I suggested some kind of
- Tove (4/6) Apr 24 2013 how about?
- bearophile (5/7) Apr 24 2013 Today we usually write it this way:
- =?UTF-8?B?Ikx1w61z?= Marques" (2/4) Apr 24 2013 Thanks. (I just copied it from the docs)
- Idan Arye (9/17) Apr 24 2013 Token strings solve all the problems the OP mentioned, but they
- =?UTF-8?B?Ikx1w61z?= Marques" (19/27) Apr 24 2013 Yeah, it was unfortunate that the problems I exemplified could be
- ixid (2/8) Apr 24 2013 Is changing the language the right approach to this or would
- =?UTF-8?B?Ikx1w61z?= Marques" (17/19) Apr 24 2013 A smarter IDE always helps :-)
- renoX (6/6) Apr 26 2013 Are you really saying that 'sort!((a, b) => a > b)(array);' is
- Idan Arye (6/9) Apr 26 2013 Sure there is - it's called "convention". Since all the functions
Consider: sort!("a > b")(array); This is almost perfect, except for "a > b" being a string instead of "real" code. If "a > b" was an actual block of code it could be syntax highlighted by the editor, directly grammar checked by compiler, etc. The only impediment to that is that a and b are declared in the sort() body scope, so "a > b" has to be mixed-in later in sort(). An alternative is using a lambda: sort!((a, b) => a > b)(array); Now we have code which is directly parsed and highlighted, but it is more verbose (is there any other difference? I suppose there's no performance penalty, because the templated sort() creates a function from the string "a > b" anyway). It would seem that the best of both worlds would be for sort() to specify that the "less" type parameter could be actual code, but that it should be mixed-in inside sort(). Well, since we have lazy parameters, I was wondering why couldn't we have mixin parameters. So I tried this, which works: // create our "a > b" as code (not string) that is mixed-in later mixin template Greater() { auto Greater = () => a > b; } // example of a sort which supports template mixins void foo_sort(alias G = Greater, Range)(Range r) { bool funG(Range)(ElementType!(Range) a, ElementType!(Range) b) { mixin G; return Greater(); // Greater() because G() doesn't work (unhelpful alias, see previous thread) } sort!(funG!(Range))(r); } void main() { int[] array = [3, 1, 5, 2, 7]; foo_sort!(Greater)(array); writefln("%s", array); } So, the infrastructure seems to be there, we just had to declare Greater() outside the sort() call site because we have neither mixin template parameters nor mixin template literals. If we had one of those we could do either: void foo_sort(mixin G, Range)(Range r) { ... } // or mixin template G foo_sort!(a > b)(array); or foo_sort!({a > b})(array); // some kind of mixin template literal Of course, this isn't anything specific to template functions and sort. This is a kind of macro, just like the lazy type specifier, so I it would be useful in other places. OK, so this is probably a bit crazy, but I had to share these thoughts. Feel free to proceed to demolish all of this ;-)
Apr 23 2013
One way this could be done is by expanding on lazy parameters. Perhaps you could specify parameters for a lazy argument, so instead of always getting a delegate of type T delegate(), you could get one of type T delegate(U a, V b). For example, a parameter could be: void f(lazy bool exp(int a, int b)) { bool result = exp(1, 2); } Then when you call that: f(a < b) The names 'a' and 'b' come from the parameter list for 'f'. I would definitely vote for this as a feature!
Apr 24 2013
On 04/24/2013 07:07 PM, Diggory wrote:One way this could be done is by expanding on lazy parameters. Perhaps you could specify parameters for a lazy argument, so instead of always getting a delegate of type T delegate(), you could get one of type T delegate(U a, V b). For example, a parameter could be: void f(lazy bool exp(int a, int b)) { bool result = exp(1, 2); } Then when you call that: f(a < b) The names 'a' and 'b' come from the parameter list for 'f'. I would definitely vote for this as a feature!This is a little dangerous as it looks like an ordinary expression but has to somehow affect symbol scoping.
Apr 24 2013
On Wednesday, 24 April 2013 at 20:32:16 UTC, Timon Gehr wrote:On 04/24/2013 07:07 PM, Diggory wrote:Surely it's no more dangerous than lazy parameters already are. (they are already converted into a hidden delegate, it just happens to take no parameters at the moment)One way this could be done is by expanding on lazy parameters. Perhaps you could specify parameters for a lazy argument, so instead of always getting a delegate of type T delegate(), you could get one of type T delegate(U a, V b). For example, a parameter could be: void f(lazy bool exp(int a, int b)) { bool result = exp(1, 2); } Then when you call that: f(a < b) The names 'a' and 'b' come from the parameter list for 'f'. I would definitely vote for this as a feature!This is a little dangerous as it looks like an ordinary expression but has to somehow affect symbol scoping.
Apr 24 2013
On 04/24/2013 11:03 PM, Diggory wrote:On Wednesday, 24 April 2013 at 20:32:16 UTC, Timon Gehr wrote:It surely is. 'lazy' parameters do not affect symbol lookup in the passed expressions.On 04/24/2013 07:07 PM, Diggory wrote:Surely it's no more dangerous than lazy parameters already are. (they are already converted into a hidden delegate, it just happens to take no parameters at the moment)One way this could be done is by expanding on lazy parameters. Perhaps you could specify parameters for a lazy argument, so instead of always getting a delegate of type T delegate(), you could get one of type T delegate(U a, V b). For example, a parameter could be: void f(lazy bool exp(int a, int b)) { bool result = exp(1, 2); } Then when you call that: f(a < b) The names 'a' and 'b' come from the parameter list for 'f'. I would definitely vote for this as a feature!This is a little dangerous as it looks like an ordinary expression but has to somehow affect symbol scoping.
Apr 24 2013
On Wednesday, 24 April 2013 at 20:32:16 UTC, Timon Gehr wrote:That's true, and that was one reason I suggested some kind of template mixin literal. On the other hand, that's just an extreme version of what happens with lazy, where at the call site you can't tell that the argument side effects are not produced immediately. Without experience with features like this it's hard to tell if their usefulness pays for their cost, but it seems to me that something like this could make for very powerful macros. On Wednesday, 24 April 2013 at 17:38:34 UTC, Tove wrote:Then when you call that: f(a < b)This is a little dangerous as it looks like an ordinary expression but has to somehow affect symbol scoping.how about? sort!(q{a > b})(array); http://dlang.org/lex.html#TokenStringI was not aware of the token strings, is that new? Boy, I really should spend more time around here. That's an excellent suggestion, although I think these "mixin parameters" we are discussing are more like mixin template parameters than mixin string parameters.
Apr 24 2013
On Wednesday, 24 April 2013 at 02:18:07 UTC, Luís Marques wrote:Consider: sort!("a > b")(array);how about? sort!(q{a > b})(array); http://dlang.org/lex.html#TokenString
Apr 24 2013
Tove:how about? sort!(q{a > b})(array);Today we usually write it this way: array.sort!q{ a > b }; Bye, bearophile
Apr 24 2013
On Wednesday, 24 April 2013 at 20:50:31 UTC, bearophile wrote:Today we usually write it this way: array.sort!q{ a > b };Thanks. (I just copied it from the docs)
Apr 24 2013
On Wednesday, 24 April 2013 at 17:38:34 UTC, Tove wrote:On Wednesday, 24 April 2013 at 02:18:07 UTC, Luís Marques wrote:Token strings solve all the problems the OP mentioned, but they do not solve the one problem he didn't mention - closures: int[] array = [3, 1, 5, 2, 7]; int x = 4; writeln(array.filter!(a => a < x)()); // works as expected and prints "[3, 1, 2]" writeln(array.filter!q{a < x}()); // Error: undefined identifier xConsider: sort!("a > b")(array);how about? sort!(q{a > b})(array); http://dlang.org/lex.html#TokenString
Apr 24 2013
On Wednesday, 24 April 2013 at 23:42:57 UTC, Idan Arye wrote:Token strings solve all the problems the OP mentioned, but they do not solve the one problem he didn't mention - closures: int[] array = [3, 1, 5, 2, 7]; int x = 4; writeln(array.filter!(a => a < x)()); // works as expected and prints "[3, 1, 2]" writeln(array.filter!q{a < x}()); // Error: undefined identifier xYeah, it was unfortunate that the problems I exemplified could be solved by the token strings, without fulling solving the problem, making the issue seem more superficial than it is. Your example is better. Notice that my code worked for your example, if you changed it to match your scenario: // we have to move this outside of main, // because the mixin template cannot be there int[] array; int x = 4; mixin template Greater() { auto Greater = () => a < x; } (...) This seems to work. So, as I said, the infrastructure is there, we are just lacking the convenience of template mixin literals. Without that we have this unwieldy code, which otherwise seems fine.
Apr 24 2013
Consider: sort!("a > b")(array); This is almost perfect, except for "a > b" being a string instead of "real" code. If "a > b" was an actual block of code it could be syntax highlighted by the editor, directly grammar checked by compiler, etc.Is changing the language the right approach to this or would smarter IDEs possibly be a better direction?
Apr 24 2013
On Wednesday, 24 April 2013 at 23:04:02 UTC, ixid wrote:Is changing the language the right approach to this or would smarter IDEs possibly be a better direction?A smarter IDE always helps :-) It might not be worth changing the language for this (or it might), but changing the language to have first-class support of constructs like this would allow tighter checking of the mixed-in code, which seems to me to be mainly the role of the compiler, and not of the IDE. For instance, by using token strings, as suggested by Tove, you can have a tighter grip on the mixed-in string, which should lead to smarter error messages (gramatical check), but not as good as first-class support (semantic checks, etc). But I don't think this is only about error checking, it's about creating a better abstraction: I think template mixin are a less brittle abstraction than string mixins, but without the argument type modifiers they can't replace the string mixins. But don't take my opinion too seriously, I'm sure you guys know the language better than I do :-)
Apr 24 2013
Are you really saying that 'sort!((a, b) => a > b)(array);' is too verbose?? I consider 'sort!("a > b")(array);' to be **too terse**: there is nothing here telling the reader what a and b are supposed to be. BR, renoX
Apr 26 2013
On Friday, 26 April 2013 at 08:13:48 UTC, renoX wrote:I consider 'sort!("a > b")(array);' to be **too terse**: there is nothing here telling the reader what a and b are supposed to be.Sure there is - it's called "convention". Since all the functions in `std.algorithm` that accept delegates also accept string literals for a mixin that use `a` and `b` as the arguments, the reader should know what `a` and `b` means, just like they know what `sort` means.
Apr 26 2013