Jump to page: 1 2
Thread overview
Typesafe variable arguments proposal
May 03, 2004
J Anderson
May 03, 2004
J Anderson
May 04, 2004
J Anderson
May 04, 2004
J Anderson
May 05, 2004
J Anderson
May 05, 2004
J Anderson
May 04, 2004
J Anderson
May 03, 2004
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 04, 2004
Achilleas Margaritis wrote:

>"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.
>
>
>
>  
>
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/
May 04, 2004
In article <4096CC39.6090903@badmama.com.au>, J Anderson says...
>
>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/

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.


May 04, 2004
Achilleas Margaritis wrote:

>In article <4096CC39.6090903@badmama.com.au>, J Anderson says...
>  
>
>>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/
>>    
>>
>
>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.
>  
>

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;
}




>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:
>
>>In article <4096CC39.6090903@badmama.com.au>, J Anderson says...
>> 
>>
>>>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/
>>> 
>>>
>>
>>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.
>> 
>>
>
>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.

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.

>
>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;
>}
>
>
>
>
>>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.

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.

>
>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...
>  
>
>>Achilleas Margaritis wrote:
>>
>>    
>>
>>>In article <4096CC39.6090903@badmama.com.au>, J Anderson says...
>>> 
>>>
>>>      
>>>
>>>>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/
>>>>   
>>>>
>>>>        
>>>>
>>>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.
>>> 
>>>
>>>      
>>>
>>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.
>>    
>>
>
>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.
>
>  
>
>>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;
>>}
>>
>>
>>
>>
>>    
>>
>>>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.
>>    
>>
>
>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.
>
>  
>
>>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.
>  
>
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
J Anderson wrote:

> Achilleas Margaritis wrote:
>
>> 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. 

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.

> 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
"J Anderson" <REMOVEanderson@badmama.com.au> wrote in message news:c79jvi$29ct$1@digitaldaemon.com...
> J Anderson wrote:
>
> > Achilleas Margaritis wrote:
> >
> >> 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.
>
> 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.
>
> > 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/

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).



« First   ‹ Prev
1 2