www.digitalmars.com         C & C++   DMDScript  

D - Variable arguments!

reply "Vathix" <vathix dprogramming.com> writes:
We need a D way to have variable arguments soon! Here's another idea of
mine.
This might not be the best syntax but I think the ideas behind it are good.
Explanation below.


enum Base
{
 Decimal,
 Octal,
 Hex,
}


void dprint(Stream stm, typeof T args ...)
{
 foreach(T arg; args)
 {
  switch(typeof(arg))
  {
   case char[]:
    stm.writeString(arg);
    break;

   case int:
    // I'm sure this could be better optimized
    stm.writeString(std.string.toString(num));
    break;

   case bool:
    stm.writeString(arg ? "true" : "false");
    break;

   case Base:
    // Change some flag for use with printing int
    break;

   case Object:
    stm.writeString(arg.toString());
    break;

   default:
    throw new DPrintException("Unknown print type.");
  }
 }
}


void stdprint(typeof T args ...)
{
 dprint(std.stream.stdout, args);
}


void doit()
{
 stdprint(2, "hello ", "world ", 123, 456);
}


What this can internally do is pass a dynamic array of type IDs as the
parameter before a typeof... in the function call. This array won't even
need to be constructed on the fly, right? it could be in the data segment.
Any class made will work since it will call toString() on it, but I don't
know about structs and others.
Jan 03 2004
next sibling parent reply "Vathix" <vathix dprogramming.com> writes:
Realized it won't work so great for classes, might be better to do this:
case class:
 stm.writeString(arg.toString());
 break;
To find out an object's derived type, cast and check for null as usual.

All structs, unions, and enums would have a unique case, since they're not
for polymorphism; and all classes just gets one.

Would be difficult to determine unhandled type sizes so I thought they could
be assumed to be 4 unless there were 0 entries in the type array to indicate
each 4 more bytes of the current type. If I passed a long (id 1), char (id
2),
and int (id 3), the type array would be [1, 0, 2, 3].
Jan 03 2004
parent reply davepermen <davepermen_member pathlink.com> writes:
i don't see much use in it. i prefer to overload opCall instead, and write it as
()()()() wich a variable in everyone.

In article <bt6aic$2km$1 digitaldaemon.com>, Vathix says...
Realized it won't work so great for classes, might be better to do this:
case class:
 stm.writeString(arg.toString());
 break;
To find out an object's derived type, cast and check for null as usual.

All structs, unions, and enums would have a unique case, since they're not
for polymorphism; and all classes just gets one.

Would be difficult to determine unhandled type sizes so I thought they could
be assumed to be 4 unless there were 0 entries in the type array to indicate
each 4 more bytes of the current type. If I passed a long (id 1), char (id
2),
and int (id 3), the type array would be [1, 0, 2, 3].

Jan 03 2004
parent reply "Vathix" <vathix dprogramming.com> writes:
"davepermen" <davepermen_member pathlink.com> wrote in message
news:bt791v$1fhi$1 digitaldaemon.com...
 i don't see much use in it. i prefer to overload opCall instead, and write

 ()()()() wich a variable in everyone.

But doesn't that have the same performance problems as C++ iostream? Having to call a function repeatedly with the "this" pointer. I thought we were still looking for something better..
Jan 03 2004
parent davepermen <davepermen_member pathlink.com> writes:
the compiler can optimize the thispointer (as its constant all the time) to be
"passed" just one time (and it depends on calling convention to really hurt, or
not at all)

your require to pass types around, and switch on them. my one does not need ANY
runtime performance except direct calls to the correct functions. the same
feature c++ streams do have..

printf("%i",i) is slower than cout<<i; by default. why? because printf has to
parse the first string, analize, and then print out the int

cout<<i is the same as this:

printInteger(cout,i);

all at compile time determined. it is actually max performance you can get. the
calling overhead is a small one then (can be inlined even, if that gives
performance).

i'm still interested in getting some syntax sugar to make stream coding more
general. and i still miss the ability to have operators AS FUNCTIONS and not
member functions (because they DON'T BELONG TO MEMBERS).

the c++ streams are some of the best idea ever, for streams. the implementation
is another issue (and is very clumpsy). but the multiparameter calling design of
the streams is great.


In article <bt7e8g$1n1t$1 digitaldaemon.com>, Vathix says...
"davepermen" <davepermen_member pathlink.com> wrote in message
news:bt791v$1fhi$1 digitaldaemon.com...
 i don't see much use in it. i prefer to overload opCall instead, and write

 ()()()() wich a variable in everyone.

But doesn't that have the same performance problems as C++ iostream? Having to call a function repeatedly with the "this" pointer. I thought we were still looking for something better..

Jan 03 2004
prev sibling parent Andy Friesen <andy ikagames.com> writes:
Vathix wrote:

 We need a D way to have variable arguments soon! Here's another idea of
 mine.
 This might not be the best syntax but I think the ideas behind it are good.
 Explanation below.

XL <http://mozart-dev.sourceforge.net/xl.html> does something kind of neat, though it's a drastically different language. The ubiquitious 'Min' function is implemented as: generic type ordered if with ordered A, B with boolean C := A < B function Min(ordered A) return ordered is return A function Min(ordered A; other) return ordered is result := Min(other) if A < result then result := A 'other' is just all the successive arguments passed. It essentially compiles to Min(x, Min(y, Min(z, Min(...) ) ) ) Of course, this more or less stipulates that the function be written in a functional way, instead of imperative. (I don't know whether that's important at all or not) This approach could also cause problems with vararg functions that are too large to inline, should anybody be insane enough to pass 800 arguments to one at a time. Typical overloading rules would be able to decide what types are allowed. printf could look something like: void printf() { // Trivial base case. } void printf(int i, other) { std.c.printf("%i", i); printf(other); } void printf(char[] s, other) { std.c.printf("%.s", s); printf(other); } and so forth. --andy
Jan 03 2004