D - variable argument lists
- Achilleas Margaritis (331/331) May 23 2003 I did not find them in D, and I could not find a relevant post in the
- Ilya Minkov (3/7) May 23 2003 Consider grepping for "..." on the Phobos source. :>
- Sean L. Palmer (9/22) May 24 2003 I just recently posted some ideas almost exactly like these; look for t...
I did not find them in D, and I could not find a relevant post in the newsgroups, but I assume I did not look hard enough. Anyway, if it has not been already proposed, here is my proposition to put variable argument declarations in D: A method that receives variable arguments (printf, for example), can be declared with a single parameter '...',as in C/C++. There is no need to declare another parameter first though. Before putting the arguments on the stack, the compiler builds a table of argument information. Each entry in this table contains the type id of the entity passed on the stack and its address on the stack. Then, the programmer can use these information for accessing the objects in the stack in a safe manner. The syntax should be similar to accessing an array, only the name being predefined and considered a property of the method. For example: //class with method of variable arguments class ABC { //method with variable arguments void vaMethod(...) { for(int i = 0; i < params.size; i++) { switch (params[i].type) { case int: int v = params[i]; break; case char: char v = params[i]; break; case long: long v = params[i]; break; } } } }; //usage ABC obj; obj.vaMethod(1, 2, "string", 5.6); Of course, this technique means the following: 1) that during compilation, D enumerates all types available to the application and uses this implicit enumeration in pushing to the stack any arguments. 2) each method gets a static property which is a static array of arguments; array semantics are preserved. 3) when a parameter is accessed as a type other than what it really is, an exception should be thrown. 4) variable argument passing becomes type safe. 5) the need for format strings and parsing is (partially!!!) eliminated. 6) the D compiler must understand a special switch statement that concerns the type of the variable; this is almost the same as run-time type identification. This method can replace printf: string formatters can become objects passed on the stack that contain the value to be printed and return a string representation of the value with the given format parameters. Here is the relevant C++ example program; of course, since the compiler does not support this technique, everything is done manually: the 'param_list' class accepts up to 10 arguments, all of predefined type. Also note the existence of a 'variant' class: #include <vector> #include <string> #include <stdexcept> #include <iostream> using namespace std; typedef unsigned char byte; typedef unsigned short word; typedef unsigned long dword; typedef unsigned int uint; enum type_enum { t_none, t_char, t_short, t_long, t_int, t_byte, t_word, t_dword, t_uint, t_string }; class type_error : public runtime_error { public: type_error(const string &type) : runtime_error("invalid type:" + type) { } }; class variant { public: variant() { _type = t_none; _value.v_int = 0; } variant(char v) { _type = t_char; _value.v_char = v; } variant(short v) { _type = t_short; _value.v_short = v; } variant(long v) { _type = t_long; _value.v_long = v; } variant(int v) { _type = t_int; _value.v_int = v; } variant(byte v) { _type = t_byte; _value.v_byte = v; } variant(word v) { _type = t_word; _value.v_word = v; } variant(dword v) { _type = t_dword; _value.v_dword = v; } variant(uint v) { _type = t_uint; _value.v_uint = v; } variant(const string &v) { _type = t_string; _string = v; } variant(const char *s) { _type = t_string; _string = s; } operator char () const { if (_type != t_char) throw type_error(_type_name(_type)); return _value.v_char; } operator short () const { if (_type != t_short) throw type_error(_type_name(_type)); return _value.v_short; } operator long () const { if (_type != t_long) throw type_error(_type_name(_type)); return _value.v_long; } operator int () const { if (_type != t_int) throw type_error(_type_name(_type)); return _value.v_int; } operator byte () const { if (_type != t_byte) throw type_error(_type_name(_type)); return _value.v_byte; } operator word () const { if (_type != t_word) throw type_error(_type_name(_type)); return _value.v_word; } operator dword () const { if (_type != t_dword) throw type_error(_type_name(_type)); return _value.v_dword; } operator uint () const { if (_type != t_uint) throw type_error(_type_name(_type)); return _value.v_uint; } operator string () const { if (_type != t_string) throw type_error(_type_name(_type)); return _string; } int type() const { return _type; } private: union _Variant { char v_char; short v_short; long v_long; int v_int; byte v_byte; word v_word; dword v_dword; uint v_uint; }; int _type; _Variant _value; string _string; static string _type_name(int type) { switch (type) { case t_none: return "none"; case t_char: return "char"; case t_short: return "short"; case t_long: return "long"; case t_int: return "int"; case t_byte: return "byte"; case t_word: return "word"; case t_dword: return "dword"; case t_uint: return "uint"; case t_string: return "string"; } return ""; } }; class param_list : public vector<variant> { public: param_list(const variant &v1) { push_back(v1); } param_list(const variant &v1, const variant &v2) { push_back(v1); push_back(v2); } param_list(const variant &v1, const variant &v2, const variant &v3) { push_back(v1); push_back(v2); push_back(v3); } param_list(const variant &v1, const variant &v2, const variant &v3, const variant &v4) { push_back(v1); push_back(v2); push_back(v3); push_back(v4); } param_list(const variant &v1, const variant &v2, const variant &v3, const variant &v4, const variant &v5) { push_back(v1); push_back(v2); push_back(v3); push_back(v4); push_back(v5); } param_list(const variant &v1, const variant &v2, const variant &v3, const variant &v4, const variant &v5, const variant &v6) { push_back(v1); push_back(v2); push_back(v3); push_back(v4); push_back(v5); push_back(v6); } param_list(const variant &v1, const variant &v2, const variant &v3, const variant &v4, const variant &v5, const variant &v6, const variant &v7) { push_back(v1); push_back(v2); push_back(v3); push_back(v4); push_back(v5); push_back(v6); push_back(v7); } param_list(const variant &v1, const variant &v2, const variant &v3, const variant &v4, const variant &v5, const variant &v6, const variant &v7, const variant &v8) { push_back(v1); push_back(v2); push_back(v3); push_back(v4); push_back(v5); push_back(v6); push_back(v7); push_back(v8); } param_list(const variant &v1, const variant &v2, const variant &v3, const variant &v4, const variant &v5, const variant &v6, const variant &v7, const variant &v8, const variant &v9) { push_back(v1); push_back(v2); push_back(v3); push_back(v4); push_back(v5); push_back(v6); push_back(v7); push_back(v8); push_back(v9); } param_list(const variant &v1, const variant &v2, const variant &v3, const variant &v4, const variant &v5, const variant &v6, const variant &v7, const variant &v8, const variant &v9, const variant &v10) { push_back(v1); push_back(v2); push_back(v3); push_back(v4); push_back(v5); push_back(v6); push_back(v7); push_back(v8); push_back(v9); push_back(v10); } const variant &operator [] (int index) const { return at(index); } }; void print(const param_list ¶ms) { for(int i = 0; i < params.size(); i++) { switch (params[i].type()) { case t_char: cout << (char)params[i] << ", "; break; case t_short: cout << (short)params[i] << ", "; break; case t_long: cout << (long)params[i] << ", "; break; case t_int: cout << (int)params[i] << ", "; break; case t_byte: cout << (byte)params[i] << ", "; break; case t_word: cout << (word)params[i] << ", "; break; case t_dword: cout << (dword)params[i] << ", "; break; case t_uint: cout << (uint)params[i] << ", "; break; case t_string: cout << (string)params[i] << ", "; break; } } } int main() { char ch = 'A'; print(param_list(1, ch, 3, "yo", 5)); getchar(); return 0; }
May 23 2003
Achilleas Margaritis wrote:I did not find them in D, and I could not find a relevant post in the newsgroups, but I assume I did not look hard enough. Anyway, if it has not been already proposed, here is my proposition to put variable argument declarations in D:Consider grepping for "..." on the Phobos source. :> -i.
May 23 2003
I just recently posted some ideas almost exactly like these; look for the thread "String formatting stuff", it's pretty deep down in the thread though. Also see "typesafe varargs" thread. Sean "Achilleas Margaritis" <axilmar in.gr> wrote in message news:balid5$2q65$1 digitaldaemon.com...I did not find them in D, and I could not find a relevant post in the newsgroups, but I assume I did not look hard enough. Anyway, if it has not been already proposed, here is my proposition to put variable argument declarations in D: A method that receives variable arguments (printf, for example), can be declared with a single parameter '...',as in C/C++. There is no need to declare another parameter first though. Before putting the arguments onthestack, the compiler builds a table of argument information. Each entry in this table contains the type id of the entity passed on the stack and its address on the stack. Then, the programmer can use these information for accessing the objects in the stack in a safe manner. The syntax should be similar to accessing an array, only the name being predefined andconsidereda property of the method. For example:
May 24 2003