www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Variadic functions again

reply Andrew Edwards <ridimz_at yahoo.dot.com> writes:
This is an attempt to generate conversation on variadic functions, the
implementation of which would ultimately lesson our search for an
adequate solution to the D I/O issue.

Note: I'm often uncomfortable referring to arguments and parameters in
       speech and writing so I'll be referring to all such items as
       arguments.

------print.d------
int main()
{
   double d;
   char c;
   print(d,c);
}

void print(char[] start, ...)
{
}

-------------------
compiler errors messages:
print.d(5): function print (char[]start,...) does not match argument
types (double,char)
print.d(5): cannot implicitly convert double to char[]

Given the function print(), as defined above, it is clear to see (from
the generated error messages) that the compiler is capable of not only
discerning the total numbers of arguments used to call that function,
but also the type of each of those arguments.

IMHO it wouldn't be too unreasonable to assume that in order for it to
gather this information, the compiler must know beforehand where each of
those arguments are stored (i.e. the address of each argument) in
memory.

Now suppose for a moment that we had a built-in type-pointer, called
"variant", that points to and assumes the characteristics of any, and
all, other built-in types. Making the following legal:

   variant variable; // value automatically dereferenced to the value of
                     // whatever it points to. (Does NOT return an
                     // address and is NOT a copy!)
   void space;
   char[] string;
   int i; double j; char c; etc...

   variable = space;  // typeof(variable) -> void
   variable = string; // typeof(variable) -> char[]
   variable = i;      // typeof(variable) -> int
   variable = j;      // typeof(variable) -> double
   variable = c;      // typeof(variable) -> char
   etc...

Wouldn't this allow us to deal with variables at compile time without
knowing it's actual type?

Hold that thought for a moment!

Review of the stdarg functions reveal that variable arguments are
arranged sequentially in memory. Simply knowing the size of each argument
allows us to move from one memory location to another within the
argument list.

So what if we stored those arguments in an array (call it "sequence" if
you will) internally to the compiler whenever a variadic function is
encountered? [e.g. echo(char[] v, int i, char c, ...) or scan(...), but
                not foo(char ch) or bar()]

Wouldn't we be able to access each argument individually through array
indexing (akin to accessing arguments passed in to the main() function)?

Now suppose the array was an associative array:

   variant[int] sequence; // syntactic sugar for this would be ...

Wouldn't we be able to foreach through each of those arguments and
manipulate them without regard to type?

This functionality could drastically reduce our search for a proper I/O
facility for The D Language and completely eliminate the problem of
traversing arguments of a variadic function (thereby eliminating the
need for std.c.stdarg).

Your thoughts and opinions are greatly appreciated.

If I'm somewhere off in coocoo land, please don't be afraid to say so!!!

Thanks,
Andrew
Jun 08 2004
next sibling parent J C Calvarese <jcc7 cox.net> writes:
Andrew Edwards wrote:
 This is an attempt to generate conversation on variadic functions, the
 implementation of which would ultimately lesson our search for an
 adequate solution to the D I/O issue.
 
 Note: I'm often uncomfortable referring to arguments and parameters in
       speech and writing so I'll be referring to all such items as
       arguments.
 
 ------print.d------
 int main()
 {
   double d;
   char c;
   print(d,c);
 }
 
 void print(char[] start, ...)
 {
 }
 
 -------------------
 compiler errors messages:
 print.d(5): function print (char[]start,...) does not match argument
 types (double,char)
 print.d(5): cannot implicitly convert double to char[]
 
 Given the function print(), as defined above, it is clear to see (from
 the generated error messages) that the compiler is capable of not only
 discerning the total numbers of arguments used to call that function,
 but also the type of each of those arguments.
 
 IMHO it wouldn't be too unreasonable to assume that in order for it to
 gather this information, the compiler must know beforehand where each of
 those arguments are stored (i.e. the address of each argument) in
 memory.
 
 Now suppose for a moment that we had a built-in type-pointer, called
 "variant", that points to and assumes the characteristics of any, and
 all, other built-in types. Making the following legal:
 
   variant variable; // value automatically dereferenced to the value of
                     // whatever it points to. (Does NOT return an
                     // address and is NOT a copy!)
   void space;
   char[] string;
   int i; double j; char c; etc...
 
   variable = space;  // typeof(variable) -> void
   variable = string; // typeof(variable) -> char[]
   variable = i;      // typeof(variable) -> int
   variable = j;      // typeof(variable) -> double
   variable = c;      // typeof(variable) -> char
   etc...
 
 Wouldn't this allow us to deal with variables at compile time without
 knowing it's actual type?
 
 Hold that thought for a moment!
 
 Review of the stdarg functions reveal that variable arguments are
 arranged sequentially in memory. Simply knowing the size of each argument
 allows us to move from one memory location to another within the
 argument list.
 
 So what if we stored those arguments in an array (call it "sequence" if
 you will) internally to the compiler whenever a variadic function is
 encountered? [e.g. echo(char[] v, int i, char c, ...) or scan(...), but
                not foo(char ch) or bar()]
 
 Wouldn't we be able to access each argument individually through array
 indexing (akin to accessing arguments passed in to the main() function)?
 
 Now suppose the array was an associative array:
 
   variant[int] sequence; // syntactic sugar for this would be ...
 
 Wouldn't we be able to foreach through each of those arguments and
 manipulate them without regard to type?
 
 This functionality could drastically reduce our search for a proper I/O
 facility for The D Language and completely eliminate the problem of
 traversing arguments of a variadic function (thereby eliminating the
 need for std.c.stdarg).
 
 Your thoughts and opinions are greatly appreciated.
 
 If I'm somewhere off in coocoo land, please don't be afraid to say so!!!
 
 Thanks,
 Andrew

I think a built-in variant type would be Fantastic! It would also help us seduce programmers from all kinds of languages that have easy variant support, such as Visual Basic, VBScript, JavaScript, JScript, etc. (Of course some might also consider this a disadvantage. ;) ) Now we just need to twist Walter's arm... -- Justin (a/k/a jcc7) http://jcc_7.tripod.com/d/
Jun 08 2004
prev sibling next sibling parent Derek Parnell <derek psych.ward> writes:
On Tue, 08 Jun 2004 21:54:15 -0400, Andrew Edwards wrote:

 This is an attempt to generate conversation on variadic functions, the
 implementation of which would ultimately lesson our search for an
 adequate solution to the D I/O issue.
 
 Note: I'm often uncomfortable referring to arguments and parameters in
        speech and writing so I'll be referring to all such items as
        arguments.
 
 ------print.d------
 int main()
 {
    double d;
    char c;
    print(d,c);
 }
 
 void print(char[] start, ...)
 {
 }
 
 -------------------
 compiler errors messages:
 print.d(5): function print (char[]start,...) does not match argument
 types (double,char)
 print.d(5): cannot implicitly convert double to char[]
 
 Given the function print(), as defined above, it is clear to see (from
 the generated error messages) that the compiler is capable of not only
 discerning the total numbers of arguments used to call that function,
 but also the type of each of those arguments.
 
 IMHO it wouldn't be too unreasonable to assume that in order for it to
 gather this information, the compiler must know beforehand where each of
 those arguments are stored (i.e. the address of each argument) in
 memory.
 
 Now suppose for a moment that we had a built-in type-pointer, called
 "variant", that points to and assumes the characteristics of any, and
 all, other built-in types. Making the following legal:
 
    variant variable; // value automatically dereferenced to the value of
                      // whatever it points to. (Does NOT return an
                      // address and is NOT a copy!)
    void space;
    char[] string;
    int i; double j; char c; etc...
 
    variable = space;  // typeof(variable) -> void
    variable = string; // typeof(variable) -> char[]
    variable = i;      // typeof(variable) -> int
    variable = j;      // typeof(variable) -> double
    variable = c;      // typeof(variable) -> char
    etc...
 
 Wouldn't this allow us to deal with variables at compile time without
 knowing it's actual type?
 
 Hold that thought for a moment!
 
 Review of the stdarg functions reveal that variable arguments are
 arranged sequentially in memory. Simply knowing the size of each argument
 allows us to move from one memory location to another within the
 argument list.
 
 So what if we stored those arguments in an array (call it "sequence" if
 you will) internally to the compiler whenever a variadic function is
 encountered? [e.g. echo(char[] v, int i, char c, ...) or scan(...), but
                 not foo(char ch) or bar()]
 
 Wouldn't we be able to access each argument individually through array
 indexing (akin to accessing arguments passed in to the main() function)?
 
 Now suppose the array was an associative array:
 
    variant[int] sequence; // syntactic sugar for this would be ...
 
 Wouldn't we be able to foreach through each of those arguments and
 manipulate them without regard to type?
 
 This functionality could drastically reduce our search for a proper I/O
 facility for The D Language and completely eliminate the problem of
 traversing arguments of a variadic function (thereby eliminating the
 need for std.c.stdarg).
 
 Your thoughts and opinions are greatly appreciated.
 
 If I'm somewhere off in coocoo land, please don't be afraid to say so!!!
 
 Thanks,
 Andrew

Love it! I'm *so* used to working with polymorphic variables that I know I'll be missing them in D. And your idea will not cause compiled programs that DO NOT use the variant type to slow down any either. So, if a coder chooses to use a variant datatye then they accept the (slight) performance hit in order to use a *much* easier programming paradigm. I assume that we could work with classes and structures in this scheme too. -- Derek Melbourne, Australia 9/Jun/04 2:36:25 PM
Jun 08 2004
prev sibling parent reply Ben Hinkle <bhinkle4 juno.com> writes:
Andrew Edwards wrote:

 This is an attempt to generate conversation on variadic functions, the
 implementation of which would ultimately lesson our search for an
 adequate solution to the D I/O issue.
 
 Note: I'm often uncomfortable referring to arguments and parameters in
        speech and writing so I'll be referring to all such items as
        arguments.
 
 ------print.d------
 int main()
 {
    double d;
    char c;
    print(d,c);
 }
 
 void print(char[] start, ...)
 {
 }
 
 -------------------
 compiler errors messages:
 print.d(5): function print (char[]start,...) does not match argument
 types (double,char)
 print.d(5): cannot implicitly convert double to char[]
 
 Given the function print(), as defined above, it is clear to see (from
 the generated error messages) that the compiler is capable of not only
 discerning the total numbers of arguments used to call that function,
 but also the type of each of those arguments.
 
 IMHO it wouldn't be too unreasonable to assume that in order for it to
 gather this information, the compiler must know beforehand where each of
 those arguments are stored (i.e. the address of each argument) in
 memory.
 
 Now suppose for a moment that we had a built-in type-pointer, called
 "variant", that points to and assumes the characteristics of any, and
 all, other built-in types. Making the following legal:
 
    variant variable; // value automatically dereferenced to the value of
                      // whatever it points to. (Does NOT return an
                      // address and is NOT a copy!)
    void space;
    char[] string;
    int i; double j; char c; etc...
 
    variable = space;  // typeof(variable) -> void
    variable = string; // typeof(variable) -> char[]
    variable = i;      // typeof(variable) -> int
    variable = j;      // typeof(variable) -> double
    variable = c;      // typeof(variable) -> char
    etc...
 
 Wouldn't this allow us to deal with variables at compile time without
 knowing it's actual type?
 
 Hold that thought for a moment!
 
 Review of the stdarg functions reveal that variable arguments are
 arranged sequentially in memory. Simply knowing the size of each argument
 allows us to move from one memory location to another within the
 argument list.
 
 So what if we stored those arguments in an array (call it "sequence" if
 you will) internally to the compiler whenever a variadic function is
 encountered? [e.g. echo(char[] v, int i, char c, ...) or scan(...), but
                 not foo(char ch) or bar()]
 
 Wouldn't we be able to access each argument individually through array
 indexing (akin to accessing arguments passed in to the main() function)?
 
 Now suppose the array was an associative array:
 
    variant[int] sequence; // syntactic sugar for this would be ...

 Wouldn't we be able to foreach through each of those arguments and
 manipulate them without regard to type?

 This functionality could drastically reduce our search for a proper I/O
 facility for The D Language and completely eliminate the problem of
 traversing arguments of a variadic function (thereby eliminating the
 need for std.c.stdarg).
 
 Your thoughts and opinions are greatly appreciated.
 
 If I'm somewhere off in coocoo land, please don't be afraid to say so!!!
 
 Thanks,
 Andrew

three thoughts come to mind: 1) variant feels very close to Object except variant also works for primitive types (reminds me of post long ago about boxing/unboxing or wrapping primitive types) 2) have you looked into using a struct like struct variant { TypeInfo* ti; void* data; } 3) variant is somewhat like a plain old void* since it isn't clear what "manipulate them without regard to type" would mean in a compiled language. What operations should be supported by a variant? addition? toString? printf? I think this is an interesting topic but is hard to work into a compiled language where there isn't any RTTI for primitive types.
Jun 09 2004
parent Andrew Edwards <Andrew_member pathlink.com> writes:
In article <ca70oe$2adn$1 digitaldaemon.com>, Ben Hinkle says...
Andrew Edwards wrote:

 This is an attempt to generate conversation on variadic functions, the
 implementation of which would ultimately lesson our search for an
 adequate solution to the D I/O issue.
 
 Note: I'm often uncomfortable referring to arguments and parameters in
        speech and writing so I'll be referring to all such items as
        arguments.
 
 ------print.d------
 int main()
 {
    double d;
    char c;
    print(d,c);
 }
 
 void print(char[] start, ...)
 {
 }
 
 -------------------
 compiler errors messages:
 print.d(5): function print (char[]start,...) does not match argument
 types (double,char)
 print.d(5): cannot implicitly convert double to char[]
 
 Given the function print(), as defined above, it is clear to see (from
 the generated error messages) that the compiler is capable of not only
 discerning the total numbers of arguments used to call that function,
 but also the type of each of those arguments.
 
 IMHO it wouldn't be too unreasonable to assume that in order for it to
 gather this information, the compiler must know beforehand where each of
 those arguments are stored (i.e. the address of each argument) in
 memory.
 
 Now suppose for a moment that we had a built-in type-pointer, called
 "variant", that points to and assumes the characteristics of any, and
 all, other built-in types. Making the following legal:
 
    variant variable; // value automatically dereferenced to the value of
                      // whatever it points to. (Does NOT return an
                      // address and is NOT a copy!)
    void space;
    char[] string;
    int i; double j; char c; etc...
 
    variable = space;  // typeof(variable) -> void
    variable = string; // typeof(variable) -> char[]
    variable = i;      // typeof(variable) -> int
    variable = j;      // typeof(variable) -> double
    variable = c;      // typeof(variable) -> char
    etc...
 
 Wouldn't this allow us to deal with variables at compile time without
 knowing it's actual type?
 
 Hold that thought for a moment!
 
 Review of the stdarg functions reveal that variable arguments are
 arranged sequentially in memory. Simply knowing the size of each argument
 allows us to move from one memory location to another within the
 argument list.
 
 So what if we stored those arguments in an array (call it "sequence" if
 you will) internally to the compiler whenever a variadic function is
 encountered? [e.g. echo(char[] v, int i, char c, ...) or scan(...), but
                 not foo(char ch) or bar()]
 
 Wouldn't we be able to access each argument individually through array
 indexing (akin to accessing arguments passed in to the main() function)?
 
 Now suppose the array was an associative array:
 
    variant[int] sequence; // syntactic sugar for this would be ...

 Wouldn't we be able to foreach through each of those arguments and
 manipulate them without regard to type?

 This functionality could drastically reduce our search for a proper I/O
 facility for The D Language and completely eliminate the problem of
 traversing arguments of a variadic function (thereby eliminating the
 need for std.c.stdarg).
 
 Your thoughts and opinions are greatly appreciated.
 
 If I'm somewhere off in coocoo land, please don't be afraid to say so!!!
 
 Thanks,
 Andrew

three thoughts come to mind: 1) variant feels very close to Object except variant also works for primitive types (reminds me of post long ago about boxing/unboxing or wrapping primitive types)

The idea is for it to be a self-dereferencing pointer (similar to the &var of C++ or the inout parameter of D). Modifying the variant directly affects the variable to which it points, but it should facilitate pointing to a different variable later on.
2) have you looked into using a struct like
  struct variant {
    TypeInfo* ti;
    void* data;
  }

As a matter of fact I have. This, however, does not fit the bill. The variant should assume the characteristics of the variable to which it points. double trouble; // initial value nan variant var; // initial value null var = trouble; // var takes the address of trouble (var == nan) // maybe we could recall the adressof operator (&)? var = 6.66; // trouble = 6.66 typeof(var) foo; // foo is of type double printf(toString(var)); // calls toString(double)
3) variant is somewhat like a plain old void* since it isn't clear what
"manipulate them without regard to type" would mean in a compiled language.
What operations should be supported by a variant? addition? toString?
printf?

Not quite! "variant" is like a void* in the sense that it can point to anything. However, unlike void*, once it points to a variable it assumes all characteristics of that variable. If it points to an int, you can treat the variant as if it were an int. All changes made to the variant would <strong>*directly*</strong> affect the variable to which it points. Absolutely no need for casting as with void*s.
I think this is an interesting topic but is hard to work into a compiled
language where there isn't any RTTI for primitive types.

This is where I get confused. It is also the purpose of the little example provided earlier. If the compiler is capable of identifying that the incorrect number and type of arguments (and vice-versa) are used to call a function, isn't that enought information to determine the type of variable to which a variant points?
Jun 09 2004