digitalmars.D - Typesafe variable arguments proposal
- J Anderson (66/66) May 03 2004 Just starting the type safe variable arguments argument :) up again.
- Achilleas Margaritis (3/68) May 03 2004 I like the variant implementation better.
- J Anderson (4/6) May 03 2004 How would you do UDT's with it? How would you extend it?
- Achilleas Margaritis (7/14) May 04 2004 What is there to extend ? The variant type would work for any D type, ei...
- J Anderson (35/58) May 04 2004 Your thinking C++. Say to define a new type and you want to add it to
- Achilleas Margaritis (21/83) May 04 2004 If you want to add a new type to printf, you will have to change printf,...
- J Anderson (10/130) May 04 2004 I never said it couldn't be run-time. The compiler would choose. Also
- J Anderson (10/52) May 04 2004 I should add that the compiler would staticly type check everything,
- Achilleas Margaritis (9/65) May 05 2004 I don't think efficiency plays any role here. It is not that printf is u...
- J Anderson (9/17) May 05 2004 I don't buy that, not for function arguments. You can already write
- J Anderson (23/116) May 03 2004 You could also do switch statements with my proposal. Another difference...
- Achilleas Margaritis (4/124) May 05 2004 part.
Just starting the type safe variable arguments argument :) up again. I proposed something like this ages ago, I've had a bit of time to reflect and so I'll propose it again. Why not make variable arguments behave like templates: template printT(T) { void print(T t) { } } void print( ... data) { foreach (... type; data) { printT!(typeof(data)).print(data); } } //Note you could change the ... to something else for inner function part. Say I wrote something like: int a; char [] b; print(a, b); The compiler would produce a function like from the print template above, where data is a constant array. void print(int data[0], char [] data[1]) //Of course arrays like this aren't possible at the moment { foreach (... type; data) //Note this loop could be unrolled if the compiler felt like it. { printT!(typeof(data)).print(data); } } Also, it should be possible to specialize these functions (by overloading them, with the exact parameters). If you wanted to do the switch thing you could do it with if's like (which would easily be optimised): template nameof(T : bit) { char [] name() { return "bit"; } } template nameof(T : byte) { char [] name() { return "byte"; } } void print( ... data) { foreach (... type; data) { if (nameof(data) == "bit") { //... } else if (nameof(data) == "byte") { //... } } } But I wouldn't recommend it. It would also be useful to write templates with ... arguments: template funcT(... T) { void func(T data) { //... } } alias funcT(int, char[]).func func; -- -Anderson: http://badmama.com.au/~anderson/
May 03 2004
"J Anderson" <REMOVEanderson badmama.com.au> wrote in message news:c75c6f$1sdd$1 digitaldaemon.com...Just starting the type safe variable arguments argument :) up again. I proposed something like this ages ago, I've had a bit of time to reflect and so I'll propose it again. Why not make variable arguments behave like templates: template printT(T) { void print(T t) { } } void print( ... data) { foreach (... type; data) { printT!(typeof(data)).print(data); } } //Note you could change the ... to something else for inner function part. Say I wrote something like: int a; char [] b; print(a, b); The compiler would produce a function like from the print template above, where data is a constant array. void print(int data[0], char [] data[1]) //Of course arrays like this aren't possible at the moment { foreach (... type; data) //Note this loop could be unrolled if the compiler felt like it. { printT!(typeof(data)).print(data); } } Also, it should be possible to specialize these functions (by overloading them, with the exact parameters). If you wanted to do the switch thing you could do it with if's like (which would easily be optimised): template nameof(T : bit) { char [] name() { return "bit"; } } template nameof(T : byte) { char [] name() { return "byte"; } } void print( ... data) { foreach (... type; data) { if (nameof(data) == "bit") { //... } else if (nameof(data) == "byte") { //... } } } But I wouldn't recommend it. It would also be useful to write templates with ... arguments: template funcT(... T) { void func(T data) { //... } } alias funcT(int, char[]).func func; -- -Anderson: http://badmama.com.au/~anderson/I like the variant implementation better.
May 03 2004
Achilleas Margaritis wrote:I like the variant implementation better.How would you do UDT's with it? How would you extend it? -- -Anderson: http://badmama.com.au/~anderson/
May 03 2004
In article <4096CC39.6090903 badmama.com.au>, J Anderson says...Achilleas Margaritis wrote:What is there to extend ? The variant type would work for any D type, either primitive or user-defined. And by using RTTI, one could safely access the data. A variant type would also be useful in other situations; for example exchanging data without regard to the data type, implementing reflection etc. C++ can easily do variants using templates. Unfortunately, the standard vararg implementation ignores this possibility.I like the variant implementation better.How would you do UDT's with it? How would you extend it? -- -Anderson: http://badmama.com.au/~anderson/
May 04 2004
Achilleas Margaritis wrote:In article <4096CC39.6090903 badmama.com.au>, J Anderson says...Your thinking C++. Say to define a new type and you want to add it to printf (or whatever the new function is called). You can't go and change printf. With the version I propose you'd do something like this: module X; //You can't change this module void print( ... data) { foreach (... type; data) { printT!(typeof(data)).print(data); } } module Y; class A {} template printT(T : A) //Add printf for A { void print(T t) { ... } } int main() { A a; printf(a); return 1; }Achilleas Margaritis wrote:What is there to extend ? The variant type would work for any D type, either primitive or user-defined. And by using RTTI, one could safely access the data.I like the variant implementation better.How would you do UDT's with it? How would you extend it? -- -Anderson: http://badmama.com.au/~anderson/A variant type would also be useful in other situations; for example exchanging data without regard to the data type, implementing reflection etc.I've already shown how a variant type could be done. It seems a variant type from your point of view contains extra run-time costs as well. If you wish ... could be called sequence. The difference is in the interpretation. You shouldn't need to use a switch statement but u can if your inclined. -- -Anderson: http://badmama.com.au/~anderson/
May 04 2004
In article <c78334$2vl2$1 digitaldaemon.com>, J Anderson says...Achilleas Margaritis wrote:If you want to add a new type to printf, you will have to change printf, because you will have to add a new format specifier.In article <4096CC39.6090903 badmama.com.au>, J Anderson says...Your thinking C++. Say to define a new type and you want to add it to printf (or whatever the new function is called). You can't go and change printf.Achilleas Margaritis wrote:What is there to extend ? The variant type would work for any D type, either primitive or user-defined. And by using RTTI, one could safely access the data.I like the variant implementation better.How would you do UDT's with it? How would you extend it? -- -Anderson: http://badmama.com.au/~anderson/With the version I propose you'd do something like this: module X; //You can't change this module void print( ... data) { foreach (... type; data) { printT!(typeof(data)).print(data); } } module Y; class A {} template printT(T : A) //Add printf for A { void print(T t) { ... } } int main() { A a; printf(a); return 1; }It is quite useful to have a variant type. Sometimes I don't need a variable number of parameters, and I don't care about the type.A variant type would also be useful in other situations; for example exchanging data without regard to the data type, implementing reflection etc.I've already shown how a variant type could be done. It seems a variant type from your point of view contains extra run-time costs as well.If you wish ... could be called sequence. The difference is in the interpretation. You shouldn't need to use a switch statement but u can if your inclined. -- -Anderson: http://badmama.com.au/~anderson/What you are proposing is basically an automation of function overloading. The compiler would produce different versions of printf according to parameters. This can already be done manually. Do you really see a wide range of usage for such a capability to be embedded in the language ? the only place I see varargs useful is in printf, and I don't think printf execution is critical one...with your solution, an executable will be bloated with lots of printf versions; with the variants solution, only one printf needs to exist, being a little slower in run-time. Furthermore, with your solution, the variable argument list can't be passed as a parameter to another function; whereas in the variants solution, the array of variants can be passed as a parameter to another function. This is useful in printf-style functions, because only one function can be used for the decoding, parameterized with the type of output. The variant solution solves the problems of the C-style vararg solution: type recognition and the number of parameters. And the existence of a 'variant' type gives plenty of room to implement type-agnostic architectures: drag-n-drop, reflection, COM data exchange, etc.
May 04 2004
Achilleas Margaritis wrote:In article <c78334$2vl2$1 digitaldaemon.com>, J Anderson says...I never said it couldn't be run-time. The compiler would choose. Also ... in the for-loop was the variant type. You could also write: class A { ... b; } Sequence could be a better name though. -- -Anderson: http://badmama.com.au/~anderson/Achilleas Margaritis wrote:If you want to add a new type to printf, you will have to change printf, because you will have to add a new format specifier.In article <4096CC39.6090903 badmama.com.au>, J Anderson says...Your thinking C++. Say to define a new type and you want to add it to printf (or whatever the new function is called). You can't go and change printf.Achilleas Margaritis wrote:What is there to extend ? The variant type would work for any D type, either primitive or user-defined. And by using RTTI, one could safely access the data.I like the variant implementation better.How would you do UDT's with it? How would you extend it? -- -Anderson: http://badmama.com.au/~anderson/With the version I propose you'd do something like this: module X; //You can't change this module void print( ... data) { foreach (... type; data) { printT!(typeof(data)).print(data); } } module Y; class A {} template printT(T : A) //Add printf for A { void print(T t) { ... } } int main() { A a; printf(a); return 1; }It is quite useful to have a variant type. Sometimes I don't need a variable number of parameters, and I don't care about the type.A variant type would also be useful in other situations; for example exchanging data without regard to the data type, implementing reflection etc.I've already shown how a variant type could be done. It seems a variant type from your point of view contains extra run-time costs as well.If you wish ... could be called sequence. The difference is in the interpretation. You shouldn't need to use a switch statement but u can if your inclined. -- -Anderson: http://badmama.com.au/~anderson/What you are proposing is basically an automation of function overloading. The compiler would produce different versions of printf according to parameters. This can already be done manually. Do you really see a wide range of usage for such a capability to be embedded in the language ? the only place I see varargs useful is in printf, and I don't think printf execution is critical one...with your solution, an executable will be bloated with lots of printf versions; with the variants solution, only one printf needs to exist, being a little slower in run-time. Furthermore, with your solution, the variable argument list can't be passed as a parameter to another function; whereas in the variants solution, the array of variants can be passed as a parameter to another function. This is useful in printf-style functions, because only one function can be used for the decoding, parameterized with the type of output. The variant solution solves the problems of the C-style vararg solution: type recognition and the number of parameters. And the existence of a 'variant' type gives plenty of room to implement type-agnostic architectures: drag-n-drop, reflection, COM data exchange, etc.
May 04 2004
J Anderson wrote:Achilleas Margaritis wrote:I should add that the compiler would staticly type check everything, before making use of duplicate code. Reflection would be easly supported with static sized arrays. Com -> write your own variable array. I guess there could be a dynamic version as well. But I doubt there would be much *bloat* even if the compiler rolled out all these functions, particularly because there's a greater chance of in lining things. You would end up with a much more efficient design.What you are proposing is basically an automation of function overloading. The compiler would produce different versions of printf according to parameters. This can already be done manually. Do you really see a wide range of usage for such a capability to be embedded in the language ? the only place I see varargs useful is in printf, and I don't think printf execution is critical one...with your solution, an executable will be bloated with lots of printf versions; with the variants solution, only one printf needs to exist, being a little slower in run-time. Furthermore, with your solution, the variable argument list can't be passed as a parameter to another function; whereas in the variants solution, the array of variants can be passed as a parameter to another function. This is useful in printf-style functions, because only one function can be used for the decoding, parameterized with the type of output. The variant solution solves the problems of the C-style vararg solution: type recognition and the number of parameters. And the existence of a 'variant' type gives plenty of room to implement type-agnostic architectures: drag-n-drop, reflection, COM data exchange, etc.I never said it couldn't be run-time. The compiler would choose.Also ... in the for-loop was the variant type. You could also write: class A { ... b; } Sequence could be a better name though.-- -Anderson: http://badmama.com.au/~anderson/
May 04 2004
"J Anderson" <REMOVEanderson badmama.com.au> wrote in message news:c79jvi$29ct$1 digitaldaemon.com...J Anderson wrote:I don't think efficiency plays any role here. It is not that printf is used in code where efficiency matters. On the other hand, code size matters. Imagine a program where there are lots of trace output: each different trace will be a different function. And there may be thousands (for example, one of the applications in the place I work, it is 120,000 lines of code, and it has over 10,000 TRACE lines; it is a DIS simulation with lots of custom protocols used in radars).Achilleas Margaritis wrote:I should add that the compiler would staticly type check everything, before making use of duplicate code. Reflection would be easly supported with static sized arrays. Com -> write your own variable array. I guess there could be a dynamic version as well. But I doubt there would be much *bloat* even if the compiler rolled out all these functions, particularly because there's a greater chance of in lining things. You would end up with a much more efficient design.What you are proposing is basically an automation of function overloading. The compiler would produce different versions of printf according to parameters. This can already be done manually. Do you really see a wide range of usage for such a capability to be embedded in the language ? the only place I see varargs useful is in printf, and I don't think printf execution is critical one...with your solution, an executable will be bloated with lots of printf versions; with the variants solution, only one printf needs to exist, being a little slower in run-time. Furthermore, with your solution, the variable argument list can't be passed as a parameter to another function; whereas in the variants solution, the array of variants can be passed as a parameter to another function. This is useful in printf-style functions, because only one function can be used for the decoding, parameterized with the type of output. The variant solution solves the problems of the C-style vararg solution: type recognition and the number of parameters. And the existence of a 'variant' type gives plenty of room to implement type-agnostic architectures: drag-n-drop, reflection, COM data exchange, etc.I never said it couldn't be run-time. The compiler would choose.Also ... in the for-loop was the variant type. You could also write: class A { ... b; } Sequence could be a better name though.-- -Anderson: http://badmama.com.au/~anderson/
May 05 2004
Achilleas Margaritis wrote:I don't think efficiency plays any role here. It is not that printf is used in code where efficiency matters. On the other hand, code size matters. Imagine a program where there are lots of trace output: each different trace will be a different function. And there may be thousands (for example, one of the applications in the place I work, it is 120,000 lines of code, and it has over 10,000 TRACE lines; it is a DIS simulation with lots of custom protocols used in radars).I don't buy that, not for function arguments. You can already write your own dynamic variable arrays. That is something that could be in stl. Besides even D is able to make use of repetitive codes in templates now. The compiler should be able to decide if it is going to expand (roll-out) the function or not. It's the static type checking that is most important. -- -Anderson: http://badmama.com.au/~anderson/
May 05 2004
Achilleas Margaritis wrote:"J Anderson" <REMOVEanderson badmama.com.au> wrote in message news:c75c6f$1sdd$1 digitaldaemon.com...You could also do switch statements with my proposal. Another difference I see is mine allows for a more abstract level of programming. template nameof(T : bit) { char [] name() { return "bit"; } } //Would would probably be in the std/language eventually template nameof(T : byte) { char [] name() { return "byte"; } } void print( ... data) { foreach (... type; data) { switch (nameof(data)) { case "bit" break; case "byte" break; } } } I still don't recommend the switch way of doing things. It's non-pluginable and it just looks like reflection to me. -- -Anderson: http://badmama.com.au/~anderson/Just starting the type safe variable arguments argument :) up again. I proposed something like this ages ago, I've had a bit of time to reflect and so I'll propose it again. Why not make variable arguments behave like templates: template printT(T) { void print(T t) { } } void print( ... data) { foreach (... type; data) { printT!(typeof(data)).print(data); } } //Note you could change the ... to something else for inner function part. Say I wrote something like: int a; char [] b; print(a, b); The compiler would produce a function like from the print template above, where data is a constant array. void print(int data[0], char [] data[1]) //Of course arrays like this aren't possible at the moment { foreach (... type; data) //Note this loop could be unrolled if the compiler felt like it. { printT!(typeof(data)).print(data); } } Also, it should be possible to specialize these functions (by overloading them, with the exact parameters). If you wanted to do the switch thing you could do it with if's like (which would easily be optimised): template nameof(T : bit) { char [] name() { return "bit"; } } template nameof(T : byte) { char [] name() { return "byte"; } } void print( ... data) { foreach (... type; data) { if (nameof(data) == "bit") { //... } else if (nameof(data) == "byte") { //... } } } But I wouldn't recommend it. It would also be useful to write templates with ... arguments: template funcT(... T) { void func(T data) { //... } } alias funcT(int, char[]).func func; -- -Anderson: http://badmama.com.au/~anderson/I like the variant implementation better.
May 03 2004
"J Anderson" <REMOVEanderson badmama.com.au> wrote in message news:c76q23$12h5$1 digitaldaemon.com...Achilleas Margaritis wrote:part."J Anderson" <REMOVEanderson badmama.com.au> wrote in message news:c75c6f$1sdd$1 digitaldaemon.com...Just starting the type safe variable arguments argument :) up again. I proposed something like this ages ago, I've had a bit of time to reflect and so I'll propose it again. Why not make variable arguments behave like templates: template printT(T) { void print(T t) { } } void print( ... data) { foreach (... type; data) { printT!(typeof(data)).print(data); } } //Note you could change the ... to something else for inner functionIt is reflection.You could also do switch statements with my proposal. Another difference I see is mine allows for a more abstract level of programming. template nameof(T : bit) { char [] name() { return "bit"; } } //Would would probably be in the std/language eventually template nameof(T : byte) { char [] name() { return "byte"; } } void print( ... data) { foreach (... type; data) { switch (nameof(data)) { case "bit" break; case "byte" break; } } } I still don't recommend the switch way of doing things. It's non-pluginable and it just looks like reflection to me.Say I wrote something like: int a; char [] b; print(a, b); The compiler would produce a function like from the print template above, where data is a constant array. void print(int data[0], char [] data[1]) //Of course arrays like this aren't possible at the moment { foreach (... type; data) //Note this loop could be unrolled if the compiler felt like it. { printT!(typeof(data)).print(data); } } Also, it should be possible to specialize these functions (by overloading them, with the exact parameters). If you wanted to do the switch thing you could do it with if's like (which would easily be optimised): template nameof(T : bit) { char [] name() { return "bit"; } } template nameof(T : byte) { char [] name() { return "byte"; } } void print( ... data) { foreach (... type; data) { if (nameof(data) == "bit") { //... } else if (nameof(data) == "byte") { //... } } } But I wouldn't recommend it. It would also be useful to write templates with ... arguments: template funcT(... T) { void func(T data) { //... } } alias funcT(int, char[]).func func; -- -Anderson: http://badmama.com.au/~anderson/I like the variant implementation better.
May 05 2004