www.digitalmars.com         C & C++   DMDScript  

D - variable argument lists

reply "Achilleas Margaritis" <axilmar in.gr> writes:
A cool way to do 'variable argument lists' would be to allow for methods
with a single parameter that are overloaded for various types to be
expressed with one call, using commas to separate the arguments.  For
example:

instead of
print("The quick brown fox");
print(10);
print(20.5);

one could write
print("The quick brown fox", 10, 20.5);

and then the compiler would translate it to the above. That would be
type-safe, although a little slower than the C method (because of multiple
calls), but it would improve those tedious 'print' blocks of code, as well
as being easier on the eye.
Sep 01 2003
next sibling parent reply "Walter" <walter digitalmars.com> writes:
That is an intriguing solution!

"Achilleas Margaritis" <axilmar in.gr> wrote in message
news:bivp1f$1qvj$1 digitaldaemon.com...
 A cool way to do 'variable argument lists' would be to allow for methods
 with a single parameter that are overloaded for various types to be
 expressed with one call, using commas to separate the arguments.  For
 example:

 instead of
 print("The quick brown fox");
 print(10);
 print(20.5);

 one could write
 print("The quick brown fox", 10, 20.5);

 and then the compiler would translate it to the above. That would be
 type-safe, although a little slower than the C method (because of multiple
 calls), but it would improve those tedious 'print' blocks of code, as well
 as being easier on the eye.

Sep 01 2003
parent reply "Matthew Wilson" <matthew stlsoft.org> writes:
But wouldn't it mislead the coder as to the serialisation stipulations in
multi-threaded systems?

"Walter" <walter digitalmars.com> wrote in message
news:bj0sfg$9r0$1 digitaldaemon.com...
 That is an intriguing solution!

 "Achilleas Margaritis" <axilmar in.gr> wrote in message
 news:bivp1f$1qvj$1 digitaldaemon.com...
 A cool way to do 'variable argument lists' would be to allow for methods
 with a single parameter that are overloaded for various types to be
 expressed with one call, using commas to separate the arguments.  For
 example:

 instead of
 print("The quick brown fox");
 print(10);
 print(20.5);

 one could write
 print("The quick brown fox", 10, 20.5);

 and then the compiler would translate it to the above. That would be
 type-safe, although a little slower than the C method (because of


 calls), but it would improve those tedious 'print' blocks of code, as


 as being easier on the eye.


Sep 01 2003
parent reply "Walter" <walter digitalmars.com> writes:
You lost me there!

"Matthew Wilson" <matthew stlsoft.org> wrote in message
news:bj16vn$om3$1 digitaldaemon.com...
 But wouldn't it mislead the coder as to the serialisation stipulations in
 multi-threaded systems?

 "Walter" <walter digitalmars.com> wrote in message
 news:bj0sfg$9r0$1 digitaldaemon.com...
 That is an intriguing solution!

 "Achilleas Margaritis" <axilmar in.gr> wrote in message
 news:bivp1f$1qvj$1 digitaldaemon.com...
 A cool way to do 'variable argument lists' would be to allow for



 with a single parameter that are overloaded for various types to be
 expressed with one call, using commas to separate the arguments.  For
 example:

 instead of
 print("The quick brown fox");
 print(10);
 print(20.5);

 one could write
 print("The quick brown fox", 10, 20.5);

 and then the compiler would translate it to the above. That would be
 type-safe, although a little slower than the C method (because of


 calls), but it would improve those tedious 'print' blocks of code, as


 as being easier on the eye.



Sep 02 2003
parent reply Helmut Leitner <leitner hls.via.at> writes:
Walter wrote:
 
 You lost me there!
 
 "Matthew Wilson" <matthew stlsoft.org> wrote in message
 news:bj16vn$om3$1 digitaldaemon.com...
 But wouldn't it mislead the coder as to the serialisation stipulations in
 multi-threaded systems?

 "Walter" <walter digitalmars.com> wrote in message
 news:bj0sfg$9r0$1 digitaldaemon.com...
 That is an intriguing solution!

 "Achilleas Margaritis" <axilmar in.gr> wrote in message
 news:bivp1f$1qvj$1 digitaldaemon.com...
 A cool way to do 'variable argument lists' would be to allow for



 with a single parameter that are overloaded for various types to be
 expressed with one call, using commas to separate the arguments.  For
 example:

 instead of
 print("The quick brown fox");
 print(10);
 print(20.5);

 one could write
 print("The quick brown fox", 10, 20.5);

 and then the compiler would translate it to the above. That would be
 type-safe, although a little slower than the C method (because of


 calls), but it would improve those tedious 'print' blocks of code, as


 as being easier on the eye.




I think his idea is this: Assume that could command to break up a parameter list into more than one call to the same function name. Let's use a the keyword 'serialize' for this. Then serialize print(int i) { .... } ; serialize print(char [] s) { .... }; could command the compiler to break up an arbitrary parameter list of ints and strings into separate calls: print("i=",i," j=",j,"\n"); would just be compiled as if the programmer had written: print("i="); print(i); print(" j="); print(j); print("\n"); I think it's an interesting "low level" idea, that appeals to me (as a basically C, Perl and "low level thinking" man). Although I'm not sure what the consequences are. I would still prefer a solution for a clean variable length parameter lists (like in Visual Basic!). But Achilleas idea might be the next best thing and it should be very easy to implement. Just look after each parameter whether a matching 'serialize' function exists. On the other hand, it is also unclear, whether the necessary wrapping of a variable parameter list into a clean object array will have a performance advantage. If it doesn't, then this suggestion might have a value of its own. -- Helmut Leitner leitner hls.via.at Graz, Austria www.hls-software.com
Sep 02 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Helmut Leitner" <leitner hls.via.at> wrote in message
news:3F54530C.B0855051 hls.via.at...
 Walter wrote:
 You lost me there!

 "Matthew Wilson" <matthew stlsoft.org> wrote in message
 news:bj16vn$om3$1 digitaldaemon.com...
 But wouldn't it mislead the coder as to the serialisation stipulations



 multi-threaded systems?

 "Walter" <walter digitalmars.com> wrote in message
 news:bj0sfg$9r0$1 digitaldaemon.com...
 That is an intriguing solution!

 "Achilleas Margaritis" <axilmar in.gr> wrote in message
 news:bivp1f$1qvj$1 digitaldaemon.com...
 A cool way to do 'variable argument lists' would be to allow for



 with a single parameter that are overloaded for various types to





 expressed with one call, using commas to separate the arguments.





 example:

 instead of
 print("The quick brown fox");
 print(10);
 print(20.5);

 one could write
 print("The quick brown fox", 10, 20.5);

 and then the compiler would translate it to the above. That would





 type-safe, although a little slower than the C method (because of


 calls), but it would improve those tedious 'print' blocks of code,





 well
 as being easier on the eye.




I think his idea is this: Assume that could command to break up a

 list into more than one call to the same function name. Let's use a the
 keyword 'serialize' for this. Then

    serialize print(int i) { .... } ;
    serialize print(char [] s) { .... };

 could command the compiler to break up an arbitrary parameter list of ints
 and strings into separate calls:

   print("i=",i,"  j=",j,"\n");

 would just be compiled as if the programmer had written:

   print("i=");
   print(i);
   print("  j=");
   print(j);
   print("\n");

 I think it's an interesting "low level" idea, that appeals to me (as a

 Perl and "low level thinking" man). Although I'm not sure what the

 I would still prefer a solution for a clean variable length parameter

 (like in Visual Basic!).

 But Achilleas idea might be the next best thing and it should be very easy

 Just look after each parameter whether a matching 'serialize' function

 On the other hand, it is also unclear, whether the necessary wrapping of a

 parameter list into a clean object array will have a performance

 If it doesn't, then this suggestion might have a value of its own.

It seems at first blush like a pretty good idea. I'm worrying that there's a gotcha I'm not seeing. It does seem to rather neatly solve the typesafe problem.
Sep 02 2003
next sibling parent reply Helmut Leitner <leitner hls.via.at> writes:
Walter wrote:
 It seems at first blush like a pretty good idea. I'm worrying that there's a
 gotcha I'm not seeing. It does seem to rather neatly solve the typesafe
 problem.

And there would be a number of nice uses e. g. serialize drawto(int x,int y); moveto(0,0); drawto(10,0,10,10,0,10,0,0); or (in connection with the last example): serialize print(Format f,int i); print("i=",i,Format("j= %06x\n"),j); ==== Problems might come from needing a 'sticky' parameter type that would have to be repeated on all subsequent calls: serialize fprintf(sticky FILE f,char [] s); serialize fprintf(sticky FILE f,int i); because fprintf(f,"i=",i); should transform to fprintf(f,"i="); fprintf(f,i); although even this might also be easy to implement: after a serialize call resolution just keep the 'sticky' parameters. But I share your feelings. It almost looks too good and simple. There must be some hidden traps. -- Helmut Leitner leitner hls.via.at Graz, Austria www.hls-software.com
Sep 02 2003
parent "Philippe Mori" <philippe_mori hotmail.com> writes:
 Problems might come from needing a 'sticky' parameter type that would have
 to be repeated on all subsequent calls:

    serialize fprintf(sticky FILE f,char [] s);
    serialize fprintf(sticky FILE f,int i);

 because

    fprintf(f,"i=",i);

 should transform to

    fprintf(f,"i=");
    fprintf(f,i);

 although even this might also be easy to implement: after a serialize
 call resolution just keep the 'sticky' parameters.

 But I share your feelings. It almost looks too good and simple.
 There must be some hidden traps.

Then the solution would be to uses a class instead of free function (or support both). We could have something like: auto serialize class fprintf { public: this(some_args); void do_serialize(int i); void do_serialize(char [] s); } The function name could also be an operator like () or << or have a better name. Also exact modifier for classes and or functions might be changed. We could maybe support a return value but IMO exceptions would typically be used if we must terminate before reading all parameters.... Neverthless, in some case it might be interesting to support a return value to control what to do (continue with next arg, break silently, break with an error, skip next arg,...) The constructor will get first arguments (sticky parameters) and could store then as member for later uses. We could have more than one constructor provide there are no ambiguities. We could also have a destructor (that might flush the stream for example).
Sep 02 2003
prev sibling next sibling parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Walter wrote:
 "Helmut Leitner" <leitner hls.via.at> wrote in message
 news:3F54530C.B0855051 hls.via.at...
 
Walter wrote:

You lost me there!

"Matthew Wilson" <matthew stlsoft.org> wrote in message
news:bj16vn$om3$1 digitaldaemon.com...

But wouldn't it mislead the coder as to the serialisation stipulations



in
multi-threaded systems?

"Walter" <walter digitalmars.com> wrote in message
news:bj0sfg$9r0$1 digitaldaemon.com...

That is an intriguing solution!

"Achilleas Margaritis" <axilmar in.gr> wrote in message
news:bivp1f$1qvj$1 digitaldaemon.com...

A cool way to do 'variable argument lists' would be to allow for



methods
with a single parameter that are overloaded for various types to





be
expressed with one call, using commas to separate the arguments.





For
example:

instead of
print("The quick brown fox");
print(10);
print(20.5);

one could write
print("The quick brown fox", 10, 20.5);

and then the compiler would translate it to the above. That would





be
type-safe, although a little slower than the C method (because of


multiple
calls), but it would improve those tedious 'print' blocks of code,





as
well

as being easier on the eye.




I think his idea is this: Assume that could command to break up a

parameter
list into more than one call to the same function name. Let's use a the
keyword 'serialize' for this. Then

   serialize print(int i) { .... } ;
   serialize print(char [] s) { .... };

could command the compiler to break up an arbitrary parameter list of ints
and strings into separate calls:

  print("i=",i,"  j=",j,"\n");

would just be compiled as if the programmer had written:

  print("i=");
  print(i);
  print("  j=");
  print(j);
  print("\n");

I think it's an interesting "low level" idea, that appeals to me (as a

basically C,
Perl and "low level thinking" man). Although I'm not sure what the

consequences are.
I would still prefer a solution for a clean variable length parameter

lists
(like in Visual Basic!).

But Achilleas idea might be the next best thing and it should be very easy

to implement.
Just look after each parameter whether a matching 'serialize' function

exists.
On the other hand, it is also unclear, whether the necessary wrapping of a

variable
parameter list into a clean object array will have a performance

advantage.
If it doesn't, then this suggestion might have a value of its own.

It seems at first blush like a pretty good idea. I'm worrying that there's a gotcha I'm not seeing. It does seem to rather neatly solve the typesafe problem.

It makes it difficult to implement thread-safe varargs, since you have to save (thread specific) data from previous calls. In some architectures, getting/setting thread-specific data may require a syscall (to get the process or thread ID), which will impose a serious performance penalty. I earlier suggested a similar proposal, but one that passes a state variable from call to call. Although I am playing with more flexible versions, my original idea was to require that the varargs function return the same value as its first parameter. So printf would be declared with a prototype like this: varargs char[] printf(char[], ...); You would then declare various implementation functions, including the one (if desired for the case where there were no additional functions: char[] printf(char[]) { ... } char[] printf(char[], int) { ... } char[] printf(char[], char[]) { ... } and so on. When a varargs call was made, it would be turned into a recursive call of the various implementations. So the call printf("%s %d %d %d\n", str,a,b,c); would be translated into this: printf(printf(printf(printf("%s %d %d %d\n",str),a),b),c); This variation requires no thread-specific data, because the return code from each implementation is passed in as the first argument of the next impelementation. So, in the previous example, the innermost printf() will return "%d %d %d\n", the second returns "%d %d\n", and so on. The last printf() returns "".
Sep 02 2003
parent "Walter" <walter digitalmars.com> writes:
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:bj26ti$27gt$1 digitaldaemon.com...
 It seems at first blush like a pretty good idea. I'm worrying that


 gotcha I'm not seeing. It does seem to rather neatly solve the typesafe
 problem.

It makes it difficult to implement thread-safe varargs, since you have to save (thread specific) data from previous calls. In some architectures, getting/setting thread-specific data may require a syscall (to get the process or thread ID), which will impose a serious performance penalty. I earlier suggested a similar proposal, but one that passes a state variable from call to call. Although I am playing with more flexible versions, my original idea was to require that the varargs function return the same value as its first parameter. So printf would be declared with a prototype like this: varargs char[] printf(char[], ...); You would then declare various implementation functions, including the one (if desired for the case where there were no additional functions: char[] printf(char[]) { ... } char[] printf(char[], int) { ... } char[] printf(char[], char[]) { ... } and so on. When a varargs call was made, it would be turned into a recursive call of the various implementations. So the call printf("%s %d %d %d\n", str,a,b,c); would be translated into this: printf(printf(printf(printf("%s %d %d %d\n",str),a),b),c); This variation requires no thread-specific data, because the return code from each implementation is passed in as the first argument of the next impelementation. So, in the previous example, the innermost printf() will return "%d %d %d\n", the second returns "%d %d\n", and so on. The last printf() returns "".

While your idea works, what I view as the difficulty is the overhead in translating each argument into a char[]. This is the double buffering performance problem. The keeping state problem can be dealt by, as suggested by Philippe, making print() a class member and have the class object keep the state.
Sep 02 2003
prev sibling parent reply "Sean L. Palmer" <palmer.sean verizon.net> writes:
"Walter" <walter digitalmars.com> wrote in message
news:bj1nal$1i1k$1 digitaldaemon.com...
 I think his idea is this: Assume that could command to break up a

 list into more than one call to the same function name. Let's use a the
 keyword 'serialize' for this. Then

    serialize print(int i) { .... } ;
    serialize print(char [] s) { .... };

 could command the compiler to break up an arbitrary parameter list of


 and strings into separate calls:

   print("i=",i,"  j=",j,"\n");

 would just be compiled as if the programmer had written:

   print("i=");
   print(i);
   print("  j=");
   print(j);
   print("\n");


 On the other hand, it is also unclear, whether the necessary wrapping of


 variable
 parameter list into a clean object array will have a performance

 If it doesn't, then this suggestion might have a value of its own.


 It seems at first blush like a pretty good idea. I'm worrying that there's

 gotcha I'm not seeing. It does seem to rather neatly solve the typesafe
 problem.

It would. It would end up with more calls than printf, but then again doesn't printf do some calls internally? The resulting overall executable would get a bit bigger, the library code for formatting would get a bit smaller. It's alot more direct and the type safety is probably worth it. Need some overloaded print functions that take formatting structures, and this still doesn't seem to help with other streams besides the console. All stream i/o functions should be unified methinks. There shouldn't be a different function name for printing to a file or string than for printing to the console. There should be a way to get a stream interface to a string, and maybe a way to set the "current" stream so each call doesn't have to specify it. Or these print functions could be methods of a 'Stream' class. Sean Sean
Sep 02 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Sean L. Palmer" <palmer.sean verizon.net> wrote in message
news:bj2h51$2lt1$1 digitaldaemon.com...
 It would.  It would end up with more calls than printf, but then again
 doesn't printf do some calls internally?

Function overhead isn't as big a problem as double buffering each argument into separate char[]s, but the extra function calls would probably be larger than having a separate Typeinfo[] for the varargs.
 The resulting overall executable
 would get a bit bigger, the library code for formatting would get a bit
 smaller.  It's alot more direct and the type safety is probably worth it.
 Need some overloaded print functions that take formatting structures, and
 this still doesn't seem to help with other streams besides the console.

I think this problem can be dealt with by making print() a member function, as you suggest further on.
 All
 stream i/o functions should be unified methinks.  There shouldn't be a
 different function name for printing to a file or string than for printing
 to the console.  There should be a way to get a stream interface to a
 string, and maybe a way to set the "current" stream so each call doesn't
 have to specify it.  Or these print functions could be methods of a

 class.

Yes, your last statement!
Sep 02 2003
parent "Sean L. Palmer" <palmer.sean verizon.net> writes:
"Walter" <walter digitalmars.com> wrote in message
news:bj2n49$2ud9$2 digitaldaemon.com...
 "Sean L. Palmer" <palmer.sean verizon.net> wrote in message
 news:bj2h51$2lt1$1 digitaldaemon.com...
 It would.  It would end up with more calls than printf, but then again
 doesn't printf do some calls internally?

Function overhead isn't as big a problem as double buffering each argument into separate char[]s, but the extra function calls would probably be

 than having a separate Typeinfo[] for the varargs.

Listen. All I/O is buffered. Even asynchronous network transmissions. Almost all external (and some internal) devices work via DMA to/from buffers. Converting the object to a Unicode representation is work that has to be done no matter what. The problem you have is with everything being converted to string, separately, and those strings being concatenated, separately. That is wasteful. Also there is code bloat problem if all Unicode conversion has to be done separately for string stream vs. file stream. To solve that problem make everything buffered, and conversion happens to the buffer. The structure of the buffer, how the buffer gets flushed and to where is the responsibility of the other half. The stream I/O library is then how these two parts hook onto each other and how they both interface to client code. Then you get one copy of conversion for char, one for wchar, and that's that. So the argument on the language syntax end is that having an actual function call (with parameter passing overhead) for each part generates bigger code than calling one function with a TypeInfo[] argument that says how to interpret the rest of it. Very data-driven, and that's not such a bad approach. It would indeed save space. But you will want to have user-accessible versions of those conversion functions available to client code anyway right? And the implementation will walk the list and call those functions in turn based on the typeinfo's. Maybe call each object's StreamToBuffer method which invokes the low-level stream's "give me some memory to write bytes to" method. Most of the time the conversion function can give a good estimate of how much space it will need ahead of time. The "give me memory" function may not be able to provide the entire amount, at least not all at once, in one block. Maybe in several smaller blocks. Conversion functions should tolerate this. This is probably a good use for coroutines/fibers/yielding. Should there be a way to stream objects to either a textfile (and ANSI vs. Unicode?) or straight binary, or maybe by some miraculous chance to some "compatibility binary" format? Would objects derived from Streamable have to provide both? What would the sensible defaults be like? Maybe if there are sensible defaults for the basic types, larger structures would "just work". We already went through how to cut down the size of the indices to the typeinfo's. Streams should have a watchdog thread to cause them to auto-flush after a short (1/8 second?) timeout. ;) Otherwise we always have to remember to flush. Mostly this stuff are solved problems already, just find the implementation that is the best and copy its structure. What language has the best streaming facility? Oh, wait, blatant plagiarism is bad. ;) Sean
Sep 02 2003
prev sibling parent reply "Vathix" <vathix dprogramming.com> writes:
Can somebody please tell me how this idea is better than mine that I posted
a couple hours before this one, besides that it's a simpler rule? You guys
are making up all these rules to do things and my idea put it all together
nicely. With mine you could buffer output, return values, have startup and
exit code, decide which variables are "sticky" just by adding a parameter,
it would be multithread safe as far as I can tell...

Here:

void printall(this ...)
{
this(char* sz) print(sz); }
this(int i) { print(i); }
}

or

void fprintd(FILE *f, this ...)
{
this(char[] s) { c.stdio.fwrite(s, 1, s.length, f); }
this(int i) { c.stdio.fwrite(&i, i.size, 1, f); }
}


"Achilleas Margaritis" <axilmar in.gr> wrote in message
news:bivp1f$1qvj$1 digitaldaemon.com...
 A cool way to do 'variable argument lists' would be to allow for methods
 with a single parameter that are overloaded for various types to be
 expressed with one call, using commas to separate the arguments.  For
 example:

 instead of
 print("The quick brown fox");
 print(10);
 print(20.5);

 one could write
 print("The quick brown fox", 10, 20.5);

 and then the compiler would translate it to the above. That would be
 type-safe, although a little slower than the C method (because of multiple
 calls), but it would improve those tedious 'print' blocks of code, as well
 as being easier on the eye.

Sep 02 2003
next sibling parent reply Helmut Leitner <leitner hls.via.at> writes:
Vathix wrote:
 
 Can somebody please tell me how this idea is better than mine that I posted
 a couple hours before this one, besides that it's a simpler rule? You guys
 are making up all these rules to do things and my idea put it all together
 nicely. With mine you could buffer output, return values, have startup and
 exit code, decide which variables are "sticky" just by adding a parameter,
 it would be multithread safe as far as I can tell...
 
 Here:
 
 void printall(this ...)
 {
 this(char* sz) print(sz); }
 this(int i) { print(i); }
 }
 
 or
 
 void fprintd(FILE *f, this ...)
 {
 this(char[] s) { c.stdio.fwrite(s, 1, s.length, f); }
 this(int i) { c.stdio.fwrite(&i, i.size, 1, f); }
 }

I think that your idea is "perfect", but you just offer a syntax. What about the implementation? To be typesafe, the parameters passed must be organized by the compiler in some data structure, perhaps an array of objects, or an array describing the types and pointing to the various parameters. There are many ways to do it, and it needs a lot of critical and nonobvious decisions. AFAIR even Java didn't tackle this. I don't know whether C# does, although it is able to wrap/unwrap single primitives automatically. Visual Basic does, but only for a limited set of primitive types, so you can't pass a user defined structure or object. AMs idea is perhaps "worse", but it points to a simple implementation without serious flaws in performance or complexity. There may be other problems that are not jet visible. It has a certain "preprocessor touch". Does it fit into the language? Or has it the quality of a clever hack, solving a problem at hand but hindering more innovative solutions?
 "Achilleas Margaritis" <axilmar in.gr> wrote in message
 news:bivp1f$1qvj$1 digitaldaemon.com...
 A cool way to do 'variable argument lists' would be to allow for methods
 with a single parameter that are overloaded for various types to be
 expressed with one call, using commas to separate the arguments.  For
 example:

 instead of
 print("The quick brown fox");
 print(10);
 print(20.5);

 one could write
 print("The quick brown fox", 10, 20.5);

 and then the compiler would translate it to the above. That would be
 type-safe, although a little slower than the C method (because of multiple
 calls), but it would improve those tedious 'print' blocks of code, as well
 as being easier on the eye.


-- Helmut Leitner leitner hls.via.at Graz, Austria www.hls-software.com
Sep 02 2003
next sibling parent "Sean L. Palmer" <palmer.sean verizon.net> writes:
It still smells strongly of 'hack' to me.

A variable parameter list is just that, a list, but of heterogenous types,
which D's dynamic arrays does not support.

Seems like a tuple or 'in-place' struct would be an appropriate low-level
language feature, but of course printf would then need enough introspection
that it could walk the structure and print out the fields in order.

Turning the parameters into serial calls to overloaded functions is what
that machinery would ultimately do anyway, but it does seem like rather a
special case.

So far, I dislike the proposals for binding a stream 'this' pointer to each
parameter as it's peeled off.  I'm assuming D's streaming solution will take
the form of a stream class from which derives console, file, and
string/memory streams.

What if we start with the idea of a flushable buffered memory stream... you
can control the number of buffers and the size of each buffer.  For file I/O
you just set the buffer size to a disk block size,  hook up the buffer flush
to a file block write, and off you go.  For reads it'd read in a whole disk
block into the memory buffer (when a buffer is requested).  For memory
streams it'd also maintain a "list" of which memory blocks form the "file"
in memory, and buffer overflows just allocate a new block for the buffer and
hook the newly-filled block into the list.

So you could hook any functionality you want onto the buffer flush events,
and control the size of the buffering, and that way all the formatting code
lives in one place and the output goes straight to the buffer.  Yeah, the OS
can do buffering for the app, but if the runtime does the buffering, it can
use unbuffered file I/O for extra performance.

The problem is, that the printing/formatting functions must be extensible
too (hopefully without the overhead of calling an object's toString()
method, but it could do that as a last resort if there's no other print
function that matches).

In C++ they ended up with a two-level design that nobody ended up being very
happy with.

Sean

"Helmut Leitner" <leitner hls.via.at> wrote in message
news:3F54B504.BE07037E hls.via.at...
 AMs idea is perhaps "worse", but it points to a simple implementation

 serious flaws in performance or complexity. There may be other problems

 are not jet visible. It has a certain "preprocessor touch". Does it fit

 the language? Or has it the quality of a clever hack, solving a problem
 at hand but hindering more innovative solutions?

Sep 02 2003
prev sibling parent reply "Walter" <walter digitalmars.com> writes:
"Helmut Leitner" <leitner hls.via.at> wrote in message
news:3F54B504.BE07037E hls.via.at...
 AMs idea is perhaps "worse", but it points to a simple implementation

 serious flaws in performance or complexity. There may be other problems

 are not jet visible. It has a certain "preprocessor touch". Does it fit

 the language? Or has it the quality of a clever hack, solving a problem
 at hand but hindering more innovative solutions?

One issue I have with it is I still would like to have the option of embedded formatting, such as: char[] s; uint u; print("the value of ", s, " is %02x\n", u); ... serialize print(char[]); serialize print(uint); serialize print(char[] format, uint); So could 'serialized' lists of functions include functions with multiple parameters? If so, I think that some rather nasty ambiguity problems would arise.
Sep 02 2003
parent "Riccardo De Agostini" <riccardo.de.agostini email.it> writes:
"Walter" <walter digitalmars.com> ha scritto nel messaggio
news:bj2nn5$2v55$1 digitaldaemon.com...
 One issue I have with it is I still would like to have the option of
 embedded formatting, such as:
     char[] s;
     uint u;
     print("the value of ", s, " is %02x\n", u);

IMO printf-like embedded formatting, while being easy, flexible, standard, still makes it too easy to make mistakes. Once you have a separate serializable call for (char[] format, uint), another for (char[] format, ulong) etc.you may print("%08lu", x) where x is, for instance, a char... (Warning: loud thinking follows. I KNOW I'm writing horribly from the POV of anyone who knows better than me about parsers, compiler theory and the like. I'm just trying to express an idea as clearly as I can manage to). A possible solution, at least for base types, could be defining a formatting operator similar to the pseudo-op Pascal and Delphi use for formatting numbers. In Pascal you can WriteLn('The value is: ', x:8:2) which means 8 max digits, 2 decimals. Now, this is something which does not fit well in D's parser probably, because it is a special case and only works in calls to Write and WriteLn. But what if there was, say, an operator always yielding a char [] (and as such valid everywhere a char[] expression is valid) of some form like the following: <almost_any_type n> $ [ <char alignment> : ] [<short base> # ] <size_t width> [ : <size_t decimals> ] I'm giving a type to parameters so the don't have to be just constants, which allows for run-time formatting like using asterisks in printf. <char alignment> may be 'L' (default?), 'R' or 'C', with the obvious meanings of left aligned, right aligned and centered. <short base> might cause an exception or a compile-time error if <n> is a char[] or anyway not a number. Valid bases for numbers range from 2 to 36 (maybe also from -36 to -2, so there's a way to specify if one wants uppercase or lowercase letters for bases over 10). As for app-defined types, the behavior will be defined by the overloaded operator. Default (passed to the overloaded op-function if no base is specified) is 0, which for numbers should behave the same as 10. <size_t width> poses no limits if 0 (i.e. yield just as many characters as are necessary) <size_t decimals> raises an exception if it is greater than <width - 1> It comes without saying that streams _are_ necessary nonetheless, but an operator comes in handy in a lot of situations, and it could be overloaded for app-defined types, by defining an overloaded fmt() function. char [] fmt (MyType n, char alignment = 'L', short base = 0, size_t width = 0, size_t decimals = 0) Why yet another operator? Aw, come on, we format things all the time; why not make it something built into the language? What about non-significant zeros, both to the left and to the right of the decimal point? Anyone got some clue? Some examples of use: my_stream.put( n $ 'R' : 8 ); // Right aligned, 8 digits my_stream.put( customer_name $ 'L' : 50 ); // Left aligned, 50 chars max my_stream.put( error_code $ 16 # 8 ); // Hex (what about zeros?) my_stream.put( price $ 10 : 2 ); // For floating point my_stream.put( price $ 10 : (use_cents ? 2 : 0) ); // Not just constants! octal_string = my_number $ 8 # 0; // As many octal digits as necessary In case it all looks crazy, maybe it is :-) but I shared the idea just in case it's any good. Ric
Sep 03 2003
prev sibling parent "Achilleas Margaritis" <axilmar b-online.gr> writes:
I don't know if my idea is better or worse, and frankly, I don't care. I
just want the best possible programming language available(and D looks like
it!!!), and if your idea is smarter, that's ok by me.

Personally, I think that there can be two type-safe ways of doing variable
argument lists.

The 1st one I have already proposed: the programmer would combine multiple
calls of the same overloaded function into one, and the compiler would call
each method successively. It looks like a 'preprocessor hack', but so does
the use of 'add' for operator +, 'sub' for operator - etc.

The 2nd solution is to provide complete run-time information on the
variables pushed on the stack; then, a switch statement in the method would
process each argument according to its type.

The 1st solution seems more elegant to me, and the internal switch statement
of the 2nd solution would be avoided. Serialization issues are to be
resolved by a 'synchronized' keyword, ala Java (does D support multitasking
? it should, if it does not; I will search for it later), as it has already
been proposed. Printf style formatters would either passed as objects that
affect the state of the next element or as overloaded 2-argument methods.

Hack or no hack, it makes life easier, doesn't it ? I don't see why BASIC
has a 'print 10, 20, i, 5' statement and D could not have it.

"Vathix" <vathix dprogramming.com> wrote in message
news:bj29ns$2bk2$1 digitaldaemon.com...
 Can somebody please tell me how this idea is better than mine that I

 a couple hours before this one, besides that it's a simpler rule? You guys
 are making up all these rules to do things and my idea put it all together
 nicely. With mine you could buffer output, return values, have startup and
 exit code, decide which variables are "sticky" just by adding a parameter,
 it would be multithread safe as far as I can tell...

 Here:

 void printall(this ...)
 {
 this(char* sz) print(sz); }
 this(int i) { print(i); }
 }

 or

 void fprintd(FILE *f, this ...)
 {
 this(char[] s) { c.stdio.fwrite(s, 1, s.length, f); }
 this(int i) { c.stdio.fwrite(&i, i.size, 1, f); }
 }


 "Achilleas Margaritis" <axilmar in.gr> wrote in message
 news:bivp1f$1qvj$1 digitaldaemon.com...
 A cool way to do 'variable argument lists' would be to allow for methods
 with a single parameter that are overloaded for various types to be
 expressed with one call, using commas to separate the arguments.  For
 example:

 instead of
 print("The quick brown fox");
 print(10);
 print(20.5);

 one could write
 print("The quick brown fox", 10, 20.5);

 and then the compiler would translate it to the above. That would be
 type-safe, although a little slower than the C method (because of


 calls), but it would improve those tedious 'print' blocks of code, as


 as being easier on the eye.


Sep 02 2003