|
Archives
D Programming
D
D.gnu
digitalmars.D
digitalmars.D.bugs
digitalmars.D.dtl
digitalmars.D.dwt
digitalmars.D.announce
digitalmars.D.learn
digitalmars.D.debugger
C/C++ Programming
c++
c++.announce
c++.atl
c++.beta
c++.chat
c++.command-line
c++.dos
c++.dos.16-bits
c++.dos.32-bits
c++.idde
c++.mfc
c++.rtl
c++.stl
c++.stl.hp
c++.stl.port
c++.stl.sgi
c++.stlsoft
c++.windows
c++.windows.16-bits
c++.windows.32-bits
c++.wxwindows
digitalmars.empire
digitalmars.DMDScript
|
D - variable argument lists
↑ ↓ ← → "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.
↑ ↓ ← → "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.
↑ ↓ ← → "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.
↑ ↓ ← → "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.
↑ ↓ ← → 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
↑ ↓ ← → "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.
↑ ↓ ← → 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
↑ ↓ ← → "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).
↑ ↓ ← → 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 "".
↑ ↓ ← → "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.
↑ ↓ ← → "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
↑ ↓ ← → "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!
↑ ↓ ← → "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
↑ ↓ ← → "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.
↑ ↓ ← → 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
↑ ↓ ← → "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?
↑ ↓ ← → "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.
↑ ↓ ← → "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
↑ ↓ ← → "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.
|
|