digitalmars.D - Compile time variadic functions
- Oskar Linde (39/39) Mar 13 2006 Hello,
- Don Clugston (12/64) Mar 14 2006 Alias parameters almost do that. I made qualifiednameof!(alias A),
- Don Clugston (16/67) Mar 14 2006 // Just change the 'func' to decl_vararg_func to take advantage
- Oskar Linde (51/98) Mar 15 2006 Of course. How silly of me :) And it easy to add should support for
- Walter Bright (4/7) Mar 14 2006 That would be cool, but it has some severe chicken-and-egg problems. The...
- Kevin Bealer (10/18) Mar 15 2006 I think languages like SML have this feature and the associated problem ...
Hello, I recently found out a way to use D's new implicit function template instantiation support to do compile time variadic functions (http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/35151).I think it is cool enough to deserve its own post. :) I've added a slightly clumsy vararg declaration mixin to declare vararg functions. Here is a simple variadic function: template myFuncImpl(T) { void myFuncImpl(T) { static if (is (T == Empty)) { writefln("Done"); } else { writefln("Got argument %s of type %s",args.head, typeid(typeof(args.head))); .myFuncImpl(T.tail); // tail-recurse } } } struct myFuncImplDummy { mixin decl_vararg_func!(myFuncImpl); } alias myFuncImplDummy.func myFunc; And here is how it's called: void main() { myFunc(1.0,2,3L); myFunc(); } Is there any better way to do the decl_vararg_func and dummy struct thing? An identifier name template parameter type would be awesome* (I would have other uses for that as well). To be fully useful, one should add a conversion so that static array arguments are converted into dynamic arrays. Any other comments? Find the implementation including a (slightly updated) demo attached. /Oskar *) Another thing that would be nice is an auto (type inferred) return type for functions: auto func(int x) { return x+1; } Sometimes, I find myself having to write separate templates just to define a return type the compiler already knows. One example of one such template is TupleType in the attached code. (But I guess there might be a better way to write those templates...)
Mar 13 2006
Oskar Linde wrote:Hello, I recently found out a way to use D's new implicit function template instantiation support to do compile time variadic functions (http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/35151).I think it is cool enough to deserve its own post. :) I've added a slightly clumsy vararg declaration mixin to declare vararg functions. Here is a simple variadic function: template myFuncImpl(T) { void myFuncImpl(T) { static if (is (T == Empty)) { writefln("Done"); } else { writefln("Got argument %s of type %s",args.head, typeid(typeof(args.head))); .myFuncImpl(T.tail); // tail-recurse } } } struct myFuncImplDummy { mixin decl_vararg_func!(myFuncImpl); } alias myFuncImplDummy.func myFunc; And here is how it's called: void main() { myFunc(1.0,2,3L); myFunc(); } Is there any better way to do the decl_vararg_func and dummy struct thing?Probably. But this is seriously cool already.An identifier name template parameter type would be awesome* (I would have other uses for that as well).Alias parameters almost do that. I made qualifiednameof!(alias A), prettynameof!(alias A) and symbolnameof!(alias A) templates which convert identifier aliases to text. Is that any use?To be fully useful, one should add a conversion so that static array arguments are converted into dynamic arrays. Any other comments? Find the implementation including a (slightly updated) demo attached. /Oskar *) Another thing that would be nice is an auto (type inferred) return type for functions: auto func(int x) { return x+1; } Sometimes, I find myself having to write separate templates just to define a return type the compiler already knows. One example of one such template is TupleType in the attached code. (But I guess there might be a better way to write those templates...)Sounds great, but could an auto function cope with 'if' ? auto func(int x) { if (x>2) return x+1; else return Nasty!(SomeClass)(x); } In general, I think the compiler couldn't determine the type of an auto function without evaluating the templates inside it...
Mar 14 2006
Oskar Linde wrote:Hello, I recently found out a way to use D's new implicit function template instantiation support to do compile time variadic functions (http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/35151).I think it is cool enough to deserve its own post. :) I've added a slightly clumsy vararg declaration mixin to declare vararg functions. Here is a simple variadic function: template myFuncImpl(T) { void myFuncImpl(T) { static if (is (T == Empty)) { writefln("Done"); } else { writefln("Got argument %s of type %s",args.head, typeid(typeof(args.head))); .myFuncImpl(T.tail); // tail-recurse } } } struct myFuncImplDummy { mixin decl_vararg_func!(myFuncImpl); } alias myFuncImplDummy.func myFunc; And here is how it's called: void main() { myFunc(1.0,2,3L); myFunc(); } Is there any better way to do the decl_vararg_func and dummy struct thing? An identifier name template parameter type would be awesome* (I would have other uses for that as well).// Just change the 'func' to decl_vararg_func to take advantage // of implicit template name promotion. template decl_vararg_func(alias realFunc) { template decl_vararg_func(A = Empty, B = Empty, C = Empty, D = Empty, E = Empty, F = Empty, G = Empty /*, ...*/) { static void decl_vararg_func(A a = A.init, B b = B.init, C c = C.init, D d = D.init, E e = E.init, F f = F.init, G g = G.init /*,...*/) { realFunc(Tuple(a,b,c,d,e,f,g /*,...*/)); } } } // and there's no need for a mixin. alias decl_vararg_func!(funcImpl) myFunc; Which means the best effort so far is:import variadic; template myFuncImpl(T) { void myFuncImpl(T) { static if (is (T == Empty)) { writefln("Done"); } else { writefln("Got argument %s of type %s",args.head, typeid(typeof(args.head))); .myFuncImpl(T.tail); // tail-recurse } } } alias decl_vararg_func!(myFuncImpl) myFunc;> void main() {myFunc(1.0,2,3L); myFunc(); }
Mar 14 2006
Don Clugston skrev:Oskar Linde wrote:Of course. How silly of me :) And it easy to add should support for optional return values too: template decl_vararg_func(alias realFunc) { template decl_vararg_func(A = Empty, B = Empty, C = Empty, D = Empty, E = Empty, F = Empty, G = Empty /*, ...*/) { typeof(realFunc(Tuple(A.init,B.init,C.init,D.init,E.init,F.init,G.init /*,...*/))) decl_vararg_func(A a = A.init, B b = B.init, C c = C.init, D d = D.init, E e = E.init, F f = F.init, G g = G.init /*,...*/) { return realFunc(Tuple(a,b,c,d,e,f,g /*,...*/)); } } }struct myFuncImplDummy { mixin decl_vararg_func!(myFuncImpl); } alias myFuncImplDummy.func myFunc; Is there any better way to do the decl_vararg_func and dummy struct thing? An identifier name template parameter type would be awesome* (I would have other uses for that as well).// Just change the 'func' to decl_vararg_func to take advantage // of implicit template name promotion. template decl_vararg_func(alias realFunc) { template decl_vararg_func(A = Empty, B = Empty, C = Empty, D = Empty, E = Empty, F = Empty, G = Empty /*, ...*/) { static void decl_vararg_func(A a = A.init, B b = B.init, C c = C.init, D d = D.init, E e = E.init, F f = F.init, G g = G.init /*,...*/) { realFunc(Tuple(a,b,c,d,e,f,g /*,...*/)); } } } // and there's no need for a mixin. alias decl_vararg_func!(funcImpl) myFunc;Which means the best effort so far is: > import variadic; > > template myFuncImpl(T) { > void myFuncImpl(T) { > static if (is (T == Empty)) { > writefln("Done"); > } else { > writefln("Got argument %s of type %s",args.head, > typeid(typeof(args.head))); > .myFuncImpl(T.tail); // tail-recurse > } > } > } > > alias decl_vararg_func!(myFuncImpl) myFunc; > > void main() { > myFunc(1.0,2,3L); > myFunc(); > }It doesn't get any better than this (unless we get a short hand notation for function templates). Static array arguments are still a problem though. Static arrays need some special handling: - They are are the only type I know of where !is(T == typeof(T.init)) - They have schizophrenic value/reference semantics. (Behaves as a value type (declaring space) on declaration, but is a reference type otherwise) - There is no way (that I know of) to define template specializations generically for static arrays. (Only for static arrays of a defined number of elements) The first can be worked around: Change the default argument value from T.init to Init!(T): template Init(T) { const T Init = void; } The second is harder: struct Container(T) { T element; } ... Container!(typeof(x)) container; container.element = x; // Works for all types except static arrays. Meaning I have to convert static arrays into dynamic arrays: template Declare(T) { T Declare; } ... // Convert static arrays types into dynamic array types template Dynify(T) { static if (is (typeof(Declare!(T)[0]) E)) // Indexable static if (is (T : E[])) // Implicitly convertible to dynamic array alias E[] Dynify; else alias T Dynify; else alias T Dynify; } With those changes: myFunc("hello",5,2.3); works. (Attaching the code again) /Oskar
Mar 15 2006
In article <dv4j1r$eil$1 digitaldaemon.com>, Oskar Linde says...*) Another thing that would be nice is an auto (type inferred) return type for functions: auto func(int x) { return x+1; }That would be cool, but it has some severe chicken-and-egg problems. The problem is that the function body must be fully semantically analyzed before the return type can be deduced. Think of what happens when many functions call each other!
Mar 14 2006
In article <dv7mtk$1ai3$1 digitaldaemon.com>, Walter Bright says...In article <dv4j1r$eil$1 digitaldaemon.com>, Oskar Linde says...I think languages like SML have this feature and the associated problem you mention. I was told in an A.I. course that the result of adding this to the language, is that the SML compiler needs a "theorem prover" to figure out what the return type from something is. I suspect you could solve logic 101 puzzles, by reformulating them as compile time type inference problems for an SML compiler. Something like C++ metaprogramming. (I think this possibility is a pretty good argument against adding such a feature. :)) Kevin*) Another thing that would be nice is an auto (type inferred) return type for functions: auto func(int x) { return x+1; }That would be cool, but it has some severe chicken-and-egg problems. The problem is that the function body must be fully semantically analyzed before the return type can be deduced. Think of what happens when many functions call each other!
Mar 15 2006