www.digitalmars.com         C & C++   DMDScript  

D - String formatting stuff

reply Andy Friesen <andy ikagames.com> writes:
Content-Type: text/plain; charset=us-ascii; format=flowed
Content-Transfer-Encoding: 7bit

I got this idea from boost.  Seems to work pretty nicely.  Comments/etc 
welcome.

Console.io.write(format("String: '{%}' {%} + {%} = {%}") % "A string!" % 
5 % 3 % (5+3));
Mar 18 2003
next sibling parent reply "Carlos Santander B." <carlos8294 msn.com> writes:
"Andy Friesen" <andy ikagames.com> escribió en el mensaje
news:b58o2e$1rbj$1 digitaldaemon.com...
| I got this idea from boost.  Seems to work pretty nicely.  Comments/etc
| welcome.
|
| Console.io.write(format("String: '{%}' {%} + {%} = {%}") % "A string!" %
| 5 % 3 % (5+3));
|

I liked it a lot. I created console.lib merging your file with some routines
I created a while ago for handling a text console (color, clrscr, etc...
incomplete, though). I also added a write (char[] str) function for
ConsoleStream.
Anyway, I think there's some sort of mistake with the writeString(char[])
function, because if I do this:
Console.io.write("Hello, "); Console.io.write("world");
I get two lines instead of just one. Since writeString is from stream (I
assume), I think it's not your mistake.
Well, I just thought I should let you all guys know this.

-------------------------
Carlos Santander


---
Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.463 / Virus Database: 262 - Release Date: 2003-03-17
Mar 19 2003
parent reply Andy Friesen <andy ikagames.com> writes:
Carlos Santander B. wrote:
 "Andy Friesen" <andy ikagames.com> escribió en el mensaje
 news:b58o2e$1rbj$1 digitaldaemon.com...
 | I got this idea from boost.  Seems to work pretty nicely.  Comments/etc
 | welcome.
 |
 | Console.io.write(format("String: '{%}' {%} + {%} = {%}") % "A string!" %
 | 5 % 3 % (5+3));
 |
 
 I liked it a lot. I created console.lib merging your file with some routines
 I created a while ago for handling a text console (color, clrscr, etc...
 incomplete, though). I also added a write (char[] str) function for
 ConsoleStream.
 Anyway, I think there's some sort of mistake with the writeString(char[])
 function, because if I do this:
 Console.io.write("Hello, "); Console.io.write("world");
 I get two lines instead of just one. Since writeString is from stream (I
 assume), I think it's not your mistake.
 Well, I just thought I should let you all guys know this.
 
 -------------------------
 Carlos Santander
 
 
 ---
 Outgoing mail is certified Virus Free.
 Checked by AVG anti-virus system (http://www.grisoft.com).
 Version: 6.0.463 / Virus Database: 262 - Release Date: 2003-03-17
 
 

Nope. My mistake. Change the writeBlock method to read: override uint writeBlock(void* buffer, uint size) { return c.stdio.fwrite(buffer, 1, size, c.stdio.stdout); } All will be well.
Mar 19 2003
parent "Carlos Santander B." <carlos8294 msn.com> writes:
| Nope.  My mistake.  Change the writeBlock method to read:
|
|      override uint writeBlock(void* buffer, uint size)
|      {
|          return c.stdio.fwrite(buffer, 1, size, c.stdio.stdout);
|      }
|
| All will be well.
|

Thanks

-------------------------
Carlos Santander


---
Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.463 / Virus Database: 262 - Release Date: 2003-03-17
Mar 20 2003
prev sibling next sibling parent reply "Carlos Santander B." <carlos8294 msn.com> writes:
This might be to Walter, but is related to your console utility. I've added
this to Console:

import console2;
static void clear() { clrscr(); }
static void gotoxy(int x,int y) { console2.gotoxy(x,y); }
static void where (out int x,out int y) { x=wherex(); y=wherey(); }

In console2 I have:

void clrscr() {
 COORD coord;
 DWORD written;
 CONSOLE_SCREEN_BUFFER_INFO info;
 coord.X = 0;
 coord.Y = 0;
 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
 FillConsoleOutputCharacterW (GetStdHandle(STD_OUTPUT_HANDLE), ' ',
  info.dwSize.X * info.dwSize.Y, coord, &written);
 gotoxy (1, 1);
}

void gotoxy(int x, int y) {
 COORD c;
 c.X = x - 1;
 c.Y = y - 1;
 SetConsoleCursorPosition (GetStdHandle(STD_OUTPUT_HANDLE), c);
}

int wherex() {
 CONSOLE_SCREEN_BUFFER_INFO info;
 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
 return info.dwCursorPosition.X;
}

int wherey() {
 CONSOLE_SCREEN_BUFFER_INFO info;
 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
 return info.dwCursorPosition.Y - 2;
}

That's the intro. Now the problem. I have this:

import console;
void main() {
 Console.io.write('hello');
 Console.gotoxy(2,2);
 Console.io.write('world'\n);
}

But for some odd reason, DMD first processes the gotoxy function and then
both write's. I mean, it first goes to (2,2) and then prints helloworld.
What's wrong? I know that sometimes C stdout/in/err behaves weird (at least
it has happened to me on Linux), so that might be the reason. If that's so,
is it a good enough reason to get D own's stdout/in/err?

-------------------------
Carlos Santander


---
Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.463 / Virus Database: 262 - Release Date: 2003-03-17
Mar 20 2003
next sibling parent reply Andy Friesen <andy ikagames.com> writes:
Carlos Santander B. wrote:
 This might be to Walter, but is related to your console utility. I've added
 this to Console:
 
 import console2;
 static void clear() { clrscr(); }
 static void gotoxy(int x,int y) { console2.gotoxy(x,y); }
 static void where (out int x,out int y) { x=wherex(); y=wherey(); }
 
 In console2 I have:
 
 void clrscr() {
  COORD coord;
  DWORD written;
  CONSOLE_SCREEN_BUFFER_INFO info;
  coord.X = 0;
  coord.Y = 0;
  GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
  FillConsoleOutputCharacterW (GetStdHandle(STD_OUTPUT_HANDLE), ' ',
   info.dwSize.X * info.dwSize.Y, coord, &written);
  gotoxy (1, 1);
 }
 
 void gotoxy(int x, int y) {
  COORD c;
  c.X = x - 1;
  c.Y = y - 1;
  SetConsoleCursorPosition (GetStdHandle(STD_OUTPUT_HANDLE), c);
 }
 
 int wherex() {
  CONSOLE_SCREEN_BUFFER_INFO info;
  GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
  return info.dwCursorPosition.X;
 }
 
 int wherey() {
  CONSOLE_SCREEN_BUFFER_INFO info;
  GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
  return info.dwCursorPosition.Y - 2;
 }
 
 That's the intro. Now the problem. I have this:
 
 import console;
 void main() {
  Console.io.write('hello');
  Console.gotoxy(2,2);
  Console.io.write('world'\n);
 }
 
 But for some odd reason, DMD first processes the gotoxy function and then
 both write's. I mean, it first goes to (2,2) and then prints helloworld.
 What's wrong? I know that sometimes C stdout/in/err behaves weird (at least
 it has happened to me on Linux), so that might be the reason. If that's so,
 is it a good enough reason to get D own's stdout/in/err?
 
 -------------------------
 Carlos Santander
 
 
 ---
 Outgoing mail is certified Virus Free.
 Checked by AVG anti-virus system (http://www.grisoft.com).
 Version: 6.0.463 / Virus Database: 262 - Release Date: 2003-03-17
 
 

It's probably buffering things. Replace the fwrite call in ConsoleStream.write with a WriteConsole call. Either that or just fflush(c.stdio.stdout) after the fwrite. Both should work.
Mar 20 2003
parent "Carlos Santander B." <carlos8294 msn.com> writes:
"Andy Friesen" <andy ikagames.com> escribió en el mensaje
news:b5dmaf$2c5d$1 digitaldaemon.com...
| It's probably buffering things.  Replace the fwrite call in
| ConsoleStream.write with a WriteConsole call.  Either that or just
| fflush(c.stdio.stdout) after the fwrite.  Both should work.
|

Thanks! fflush worked.

-------------------------
Carlos Santander


---
Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.463 / Virus Database: 262 - Release Date: 2003-03-17
Mar 20 2003
prev sibling parent reply eluusive NOMAPSsbcglobal.net writes:
Does the console module have a buffer that it only prints out on deconstruction
or when it gets to be a certain size?  You should probably have gotoxy flush
that buffer, if that's the case.

In article <b5dl9s$2bgt$1 digitaldaemon.com>,
Carlos Santander B. says...
This might be to Walter, but is related to your

this to Console:

import console2;
static void

static void gotoxy(int x,int y) { console2.gotoxy(x,y);

static void where (out int x,out int y) { x=wherex(); y=wherey(); }

In

void clrscr() {
 COORD coord;
 DWORD written;

 coord.X = 0;
 coord.Y = 0;



 gotoxy (1, 1);
}

void

 COORD c;
 c.X = x - 1;
 c.Y = y - 1;

}

int

 CONSOLE_SCREEN_BUFFER_INFO info;

 return

}

int wherey() {
 CONSOLE_SCREEN_BUFFER_INFO

 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);

}

That's the intro. Now the problem. I

import console;
void main() {
 Console.io.write('hello');

 Console.io.write('world'\n);
}

But for some odd

both write's. I mean,

What's wrong? I know that

it has happened to me on

is it a good enough reason

-------------------------
Carlos

---
Outgoing mail is certified Virus Free.
Checked by AVG

Version: 6.0.463 / Virus Database:


Mar 20 2003
parent reply Juarez Rudsatz <Juarez_member pathlink.com> writes:
Incredible Idea !

But there are two not solved problems:

1) %5.0f -> How can I format the same type in diferent ways?
- This could be easy added.

2) 
char[] s = 'This is not a number.';
format("I am printing a number here {%}") % s;

Here appear not to be a error. But if you have many parameters, you could easily
change the order, use a wrong var and another problems. The final problem is the
formatting is not type safe at compile time.
E.g: printf("This is a number %s", s);

Some solution for this ?
Mar 21 2003
parent reply "Sean L. Palmer" <seanpalmer directvinternet.com> writes:
This is why putting the printed values after the format string isn't a good
idea.

It should be:

int n=5;
char[] s = "wow";
char c = '.';
char[] fmt = format("I am printing a number here ", n, " and then a string
", s, " and finally a period", c);

But apparently printf rules, so why try anything else?

Sean

"Juarez Rudsatz" <Juarez_member pathlink.com> wrote in message
news:b5fdv1$nh2$1 digitaldaemon.com...
 Incredible Idea !

 But there are two not solved problems:

 1) %5.0f -> How can I format the same type in diferent ways?
 - This could be easy added.

 2)
 char[] s = 'This is not a number.';
 format("I am printing a number here {%}") % s;

 Here appear not to be a error. But if you have many parameters, you could

 change the order, use a wrong var and another problems. The final problem

 formatting is not type safe at compile time.
 E.g: printf("This is a number %s", s);

 Some solution for this ?

Mar 21 2003
next sibling parent reply eluusive NOMAPSsbclgobal.net writes:
Except for the fact that va_lists are not type aware.Thus the whole format
string telling print what the arguements types are. I don't know of anything
else in D that changes this. Or am i confused?

In article <b5fm9d$u9e$1 digitaldaemon.com>, Sean L. Palmer says...
This is why putting the printed values after the format string isn't a good
idea.

It should be:

int n=5;
char[] s = "wow";
char c = '.';
char[] fmt = format("I am printing a number here ", n, " and then a string
", s, " and finally a period", c);

But apparently printf rules, so why try anything else?

Sean

Mar 21 2003
parent "Walter" <walter digitalmars.com> writes:
<eluusive NOMAPSsbclgobal.net> wrote in message
news:b5ftto$14es$1 digitaldaemon.com...
 Except for the fact that va_lists are not type aware.Thus the whole format
 string telling print what the arguements types are. I don't know of

 else in D that changes this. Or am i confused?

No, you're not confused. Variable argument lists in D work just like they do in C/C++.
Apr 03 2003
prev sibling next sibling parent reply Ilya Minkov <midiclub 8ung.at> writes:
Format string are not that bad. Consider: we are living in an 
international world. Your format string needs not be stored in the 
program, it may be in the database. Different languages may have 
different order of words.

The solution would be a formatting operator which would take a format 
string on the left side, and an associative array of strings at the 
right side. The format string would then contain parameter names, which 
would be then have to be contained as indizes in an assoziative array. 
I'm not exactly sure whether there's a convinient way to define an 
associative array literal in D in-line, IMO there should. If there 
isn't, a multiarg function can be created to take pairs of string 
literals and make an assoziative aray out of them. Obviously, this is 
even more time-consuming than simple format-string procesing. But where 
"time matters", Sean's format function serves much better than printf.

Compile-time typechecking can not be expessed in terms of the D language 
and would thus requiere to be "special"...

-i.

Sean L. Palmer wrote:
 This is why putting the printed values after the format string isn't a good
 idea.
 
 It should be:
 
 int n=5;
 char[] s = "wow";
 char c = '.';
 char[] fmt = format("I am printing a number here ", n, " and then a string
 ", s, " and finally a period", c);
 
 But apparently printf rules, so why try anything else?
 
 Sean

Mar 22 2003
parent Andy Friesen <andy ikagames.com> writes:
Ilya Minkov wrote:
 Format string are not that bad. Consider: we are living in an 
 international world. Your format string needs not be stored in the 
 program, it may be in the database. Different languages may have 
 different order of words.
 
 The solution would be a formatting operator which would take a format 
 string on the left side, and an associative array of strings at the 
 right side. The format string would then contain parameter names, which 
 would be then have to be contained as indizes in an assoziative array. 
 I'm not exactly sure whether there's a convinient way to define an 
 associative array literal in D in-line, IMO there should. If there 
 isn't, a multiarg function can be created to take pairs of string 
 literals and make an assoziative aray out of them. Obviously, this is 
 even more time-consuming than simple format-string procesing. But where 
 "time matters", Sean's format function serves much better than printf.
 
 Compile-time typechecking can not be expessed in terms of the D language 
 and would thus requiere to be "special"...
 
 -i.

I was thinking about allowing some type information in the insertion string, and then having the formatter throw an exception if the expected type is not given. Something like: format("Name: {%s}\tAge: {%i}\tpi: {%f3.8}") % name % age % pi; Where the %f bit is for precision. The alternative is to just copy printf's syntax, which, come to think of it, is probably better because of the familiarity factor. Compile-time checking could be done, but I doubt it's worth it. You'd have to chain methods. format("blah {%} {%}").insertString("blah").insertFloat(3.14); // ew By the way, I coded that, not Sean. :) (he added the console methods for repositioning the cursor, and colouring things) --andy
Mar 22 2003
prev sibling parent reply "Walter" <walter digitalmars.com> writes:
"Sean L. Palmer" <seanpalmer directvinternet.com> wrote in message
news:b5fm9d$u9e$1 digitaldaemon.com...
 This is why putting the printed values after the format string isn't a

 idea.

 It should be:

 int n=5;
 char[] s = "wow";
 char c = '.';
 char[] fmt = format("I am printing a number here ", n, " and then a string
 ", s, " and finally a period", c);

 But apparently printf rules, so why try anything else?

Why, indeed <g>. Note that printf also results in the smallest code generated.
Apr 03 2003
parent reply "Sean L. Palmer" <palmer.sean verizon.net> writes:
I'm not so sure about that.

A) printf has to parse all those format specifiers.  That slows printing
down.
B) printf pulls in all the formatting and conversion functions even if you
just want to do this:

printf("Hello world");

Maybe in certain cases it results in smaller code, but not in every case.

Sean

"Walter" <walter digitalmars.com> wrote in message
news:b6ieen$udg$3 digitaldaemon.com...
 But apparently printf rules, so why try anything else?

Why, indeed <g>. Note that printf also results in the smallest code generated.

Apr 04 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Sean L. Palmer" <palmer.sean verizon.net> wrote in message
news:b6jf3b$1m3r$1 digitaldaemon.com...
 I'm not so sure about that.

 A) printf has to parse all those format specifiers.  That slows printing
 down.
 B) printf pulls in all the formatting and conversion functions even if you
 just want to do this:

 printf("Hello world");

 Maybe in certain cases it results in smaller code, but not in every case.

printf is the smallest code to call, although the function itself is substantial. Hence, if you have a lot of calls to printf, the savings are substantial. Me, I always thought printf should just be built in to the operating system, so every program shares one copy.
May 04 2003
next sibling parent reply "Sean L. Palmer" <palmer.sean verizon.net> writes:
printf takes a variable argument list as parameter.

Make those variable argument lists first-class, with standardized means of
manipulation, construction, and iteration.

Would it be possible to make a printf that doesn't take a string as the
first parameter?  That is what I desire:  A free-form mass of output
capabilities that can apply however I wish without having to be known
specifically at runtime or at compile time.  One that doesn't centralize the
processing of tokens like printf does.  One that is truly extensible by
everybody.  You wouldn't want to clutter up other peoples' printf's, though
it'd be nice to import printf handlers from elsewhere kinda like a module.

you could call it print.  It's like printf, but without the f.  In place of
the f, you have completely configurable output.

throw in some parameterized field justification and precision control which
grab hold of a value and modify how it ends up appearing, by building an
internal string of it and modifying that then transmitting it on.

You could have a "shuffler" structure and reshuffle order of its parameters
based on some compile time switches or constants.

List processing seems like the very act of iteration.

Is this the glimmer of an answer to your iterator problems?

Sean


"Walter" <walter digitalmars.com> wrote in message
news:b944i9$1o55$1 digitaldaemon.com...
 "Sean L. Palmer" <palmer.sean verizon.net> wrote in message
 news:b6jf3b$1m3r$1 digitaldaemon.com...
 I'm not so sure about that.

 A) printf has to parse all those format specifiers.  That slows printing
 down.
 B) printf pulls in all the formatting and conversion functions even if


 just want to do this:

 printf("Hello world");

 Maybe in certain cases it results in smaller code, but not in every


 printf is the smallest code to call, although the function itself is
 substantial. Hence, if you have a lot of calls to printf, the savings are
 substantial. Me, I always thought printf should just be built in to the
 operating system, so every program shares one copy.

May 04 2003
next sibling parent reply "Walter" <walter digitalmars.com> writes:
That would be pretty cool. Any further ideas on it?

"Sean L. Palmer" <palmer.sean verizon.net> wrote in message
news:b94ebo$20n2$1 digitaldaemon.com...
 printf takes a variable argument list as parameter.

 Make those variable argument lists first-class, with standardized means of
 manipulation, construction, and iteration.

 Would it be possible to make a printf that doesn't take a string as the
 first parameter?  That is what I desire:  A free-form mass of output
 capabilities that can apply however I wish without having to be known
 specifically at runtime or at compile time.  One that doesn't centralize

 processing of tokens like printf does.  One that is truly extensible by
 everybody.  You wouldn't want to clutter up other peoples' printf's,

 it'd be nice to import printf handlers from elsewhere kinda like a module.

 you could call it print.  It's like printf, but without the f.  In place

 the f, you have completely configurable output.

 throw in some parameterized field justification and precision control

 grab hold of a value and modify how it ends up appearing, by building an
 internal string of it and modifying that then transmitting it on.

 You could have a "shuffler" structure and reshuffle order of its

 based on some compile time switches or constants.

 List processing seems like the very act of iteration.

 Is this the glimmer of an answer to your iterator problems?

 Sean


 "Walter" <walter digitalmars.com> wrote in message
 news:b944i9$1o55$1 digitaldaemon.com...
 "Sean L. Palmer" <palmer.sean verizon.net> wrote in message
 news:b6jf3b$1m3r$1 digitaldaemon.com...
 I'm not so sure about that.

 A) printf has to parse all those format specifiers.  That slows



 down.
 B) printf pulls in all the formatting and conversion functions even if


 just want to do this:

 printf("Hello world");

 Maybe in certain cases it results in smaller code, but not in every


 printf is the smallest code to call, although the function itself is
 substantial. Hence, if you have a lot of calls to printf, the savings


 substantial. Me, I always thought printf should just be built in to the
 operating system, so every program shares one copy.


May 04 2003
parent reply "Sean L. Palmer" <palmer.sean verizon.net> writes:
For starters how about building variable parameter lists support into the
language instead of living in <stdarg.h>

They would need methods or properties to:

Get the # of parameters
Extract each parameter in a typesafe manner (applying automatic conversions
if necessary, perhaps)

Iteration seems to be the key here.  The mechanism behind iteration doesn't
seem important;  whatever the rest of the language uses would be good.
Nobody has come to a consensus about that yet?

Then stop and think:  Why should varargs be limited only to args?  Why not
make them a basic type, so they can be stored, created, manipulated kinda
like an array?

The difference between a variable argument list and a struct initializer is
that a struct has curly braces around it, and has a name, and its fields
have names.
Variable parameter lists are the same thing but with parenthesis, and
inferred type.

It's like constructing a struct from scratch, with no predetermined layout.
Blank slate.  Put anything you want in there.  And the fields don't have
names, they only have order.

In fact it's more like a block scope that can only contain data
declarations, but without names.

If you can declare those anywhere, and name, analyze and manipulate them
anywhere, well, you have:

A)  Variably-typed parameters (single-argument varargs)
B)  Pairs/Tuples
C)  Lists
D)  Easy one-off structs, when you need a struct only once and don't want to
give it a name, or give its members names.
E)  A lot of power

If you could put other things in them besides data, such as, say, types,
well then you are approaching C++ in power.

Making varargs typesafe would make printf tolerable.  I still wouldn't like
it, but I could tolerate it.  But I am not quite clear what all would be
involved.  I know it would require direct compiler support.

Sean

----- Original Message -----
From: "Walter" <walter digitalmars.com>
Newsgroups: D
Sent: Sunday, May 04, 2003 9:17 PM
Subject: Re: String formatting stuff


 That would be pretty cool. Any further ideas on it?

 "Sean L. Palmer" <palmer.sean verizon.net> wrote in message
 news:b94ebo$20n2$1 digitaldaemon.com...
 printf takes a variable argument list as parameter.

 Make those variable argument lists first-class, with standardized means


 manipulation, construction, and iteration.

 Would it be possible to make a printf that doesn't take a string as the
 first parameter?  That is what I desire:  A free-form mass of output
 capabilities that can apply however I wish without having to be known
 specifically at runtime or at compile time.  One that doesn't centralize

 processing of tokens like printf does.  One that is truly extensible by
 everybody.  You wouldn't want to clutter up other peoples' printf's,

 it'd be nice to import printf handlers from elsewhere kinda like a


 you could call it print.  It's like printf, but without the f.  In place

 the f, you have completely configurable output.

 throw in some parameterized field justification and precision control

 grab hold of a value and modify how it ends up appearing, by building an
 internal string of it and modifying that then transmitting it on.

 You could have a "shuffler" structure and reshuffle order of its

 based on some compile time switches or constants.

 List processing seems like the very act of iteration.

 Is this the glimmer of an answer to your iterator problems?

 Sean


May 05 2003
next sibling parent Ilya Minkov <midiclub 8ung.at> writes:
I'm not sure i know what varargs are for.

* They requiere you to explicitly - or implicitly secify a number of 
parameters beforehand

* They spoil the calling convention.

* They are by definition error-prone.

In C, you couldn't define an array right in your code, so the varargs 
jumped in.

What you are used to looks like this:

    printf ("format %s %d", s, b);

is it really worse than:

    printf ("format %s %d", [s,b]);

And even if you think it is, if a function expects an array, why can't 
you make the compiler turn the first into the second one? It would also 
solve the problem of "how do i write a varargs function in an easy and 
elegant manner". Either it is a relative of a printf or some other array 
or varargs function - so it gets an array and passes it further. Or it 
is a completely new beast - then it simply iterates through an array 
with standard means. And with all that: the PASCAL-like calling 
convention can be maintained, with called function doing the cleanup.

You might take a look at OpenGL. Yes, it *can* use varargs - but then 
you need to specify number of arguments explicitly. In D, where dynamic 
arrays are a part of the language, this is not requered any longer.

DUMP VARARGS! They have *really* nothing to do in D. Instead, you can 
provide an alternative calling syntax for functions accepting arrays - 
maybe other agregates as well. I believe some new agregates could be 
useful, like tuples named here -- maybe even lists...

Further comments are embedded...

Sean L. Palmer wrote:
 Then stop and think:  Why should varargs be limited only to args?  Why not
 make them a basic type, so they can be stored, created, manipulated kinda
 like an array?

Why not use an array? Varargs have never actually been for accepting different types. They are a hack, based on rudimentary C's way of handling functions without prototypes. Later, as prototypes became a requierement, a way had to be found to formalise this nonsense. Mind that you actually have to give printf *manually* all argument types in the format string?
 The difference between a variable argument list and a struct initializer is
 that a struct has curly braces around it, and has a name, and its fields
 have names.
 Variable parameter lists are the same thing but with parenthesis, and
 inferred type.

That would be a tuple. :) A useful type all by itself. I can summarise the way Sather handles tuples and console io stuff later. I know it's not state-of-the-art, but i find it appropriate for the OO environment - which is what we have here. BTW, there is a problem with a function expecting a tuple - it has to know its exact type, else we're back to dealing with an array of generics.
 A)  Variably-typed parameters (single-argument varargs)

There is a slight problem with that. It is possible in a true OO language like Sather - *everything* is a descendant of the root object, even INT and such. Note that it doesn't mean that Sather attaches a vtable to all types - it does only to those handled by reference. It also allows types handled by value, stack-allocated, which don't get a vtable ptr. They only get it when passed where an abstract object is expected - this is called boxing. :) And just like in D, abstract object defines conversion into a string. Sorry to say that, but D's OO seems like fairly half-hearted as compared to Sather.
 If you could put other things in them besides data, such as, say, types,
 well then you are approaching C++ in power.

If you get an abstract object, you don't have any problem since you can inspect its type. But in D, "lightweight" data types don't get boxed. This, BTW, is also a problem with unions - that they are typeless - would also get solved by boxing.
 Making varargs typesafe would make printf tolerable.  I still wouldn't like
 it, but I could tolerate it.  But I am not quite clear what all would be
 involved.  I know it would require direct compiler support.

There *is* a typesafe varargs printf out there. Take DLI and look in its library source. It is not included in the DMD's Version of Phobos. And take a look at "generic" type. D shows its glory sides in it. But one glory side more - and it were *much* simpler. -i.
May 06 2003
prev sibling next sibling parent "Walter" <walter digitalmars.com> writes:
Putting in types would require essentially an array of TypeInfo pointers
paralleling it.

"Sean L. Palmer" <palmer.sean verizon.net> wrote in message
news:b97f7e$1suu$1 digitaldaemon.com...
 For starters how about building variable parameter lists support into the
 language instead of living in <stdarg.h>

 They would need methods or properties to:

 Get the # of parameters
 Extract each parameter in a typesafe manner (applying automatic

 if necessary, perhaps)

 Iteration seems to be the key here.  The mechanism behind iteration

 seem important;  whatever the rest of the language uses would be good.
 Nobody has come to a consensus about that yet?

 Then stop and think:  Why should varargs be limited only to args?  Why not
 make them a basic type, so they can be stored, created, manipulated kinda
 like an array?

 The difference between a variable argument list and a struct initializer

 that a struct has curly braces around it, and has a name, and its fields
 have names.
 Variable parameter lists are the same thing but with parenthesis, and
 inferred type.

 It's like constructing a struct from scratch, with no predetermined

 Blank slate.  Put anything you want in there.  And the fields don't have
 names, they only have order.

 In fact it's more like a block scope that can only contain data
 declarations, but without names.

 If you can declare those anywhere, and name, analyze and manipulate them
 anywhere, well, you have:

 A)  Variably-typed parameters (single-argument varargs)
 B)  Pairs/Tuples
 C)  Lists
 D)  Easy one-off structs, when you need a struct only once and don't want

 give it a name, or give its members names.
 E)  A lot of power

 If you could put other things in them besides data, such as, say, types,
 well then you are approaching C++ in power.

 Making varargs typesafe would make printf tolerable.  I still wouldn't

 it, but I could tolerate it.  But I am not quite clear what all would be
 involved.  I know it would require direct compiler support.

May 06 2003
prev sibling parent reply Richard Krehbiel <rich kastle.com> writes:
In news://news.digitalmars.com/a7d9d2$qtv$1 digitaldaemon.com I wrote up 
a type-safe varargs proposal:


Start with the function declaration:

void printf(char[], PrintfParam args...)
{
// Function body


"type args..." is like "type args[]" but signals that the compiler 
should collect up the arguments into the array. "type... args" should be 
a synonym of "type args..." just as "type[] array" is the same as "type 
array[]". The body of this function treats args as if it were a regular 
dynamic array, because it is.

When a user codes:
     char[] name = "Cecil";
     printf("My name is %s\n", name);

..the compiler does the equivalent of this:

    PrintfParms[] _t;
    _t[0] = new PrintfParms(name);
    printf("My name is %s\n", _t);

Rules:

     Each function argument must be implicitly compatible with the 
argument type; else,

     Each argument must be convertible to the argument type via the 
type's constructor; else,

     The argument's not valid and the compiler prints an error.

Only the final parameter to a function can be varargs, just like C.

I like this better than the universal VARIANT type that VB uses, since 
that way allows programmers to pass types that the function doesn't 
expect, and/or requires the called function to expect every type.  The 
argument type only needs constructors for types it can deal with.

You can't make a varargs function in C which is allowed to take zero
arguments.  But with this method, you can:  void NoArgs(Type args...) 
could be called with no arguments, and would receive a zero-length array.

"<type> args..." is implicitly compatible with "<type> args[]" and, as 
such, can be passed around between functions, like C's va_list can.  But 
it's even better: you can write code to construct the a "<type> args[]", 
but you *can't* construct a va_list in C except by calling a varargs 
function.

Sean L. Palmer wrote:
 For starters how about building variable parameter lists support into the
 language instead of living in <stdarg.h>
 
 They would need methods or properties to:
 
 Get the # of parameters
 Extract each parameter in a typesafe manner (applying automatic conversions
 if necessary, perhaps)
 
 Iteration seems to be the key here.  The mechanism behind iteration doesn't
 seem important;  whatever the rest of the language uses would be good.
 Nobody has come to a consensus about that yet?
 
 Then stop and think:  Why should varargs be limited only to args?  Why not
 make them a basic type, so they can be stored, created, manipulated kinda
 like an array?
 
 The difference between a variable argument list and a struct initializer is
 that a struct has curly braces around it, and has a name, and its fields
 have names.
 Variable parameter lists are the same thing but with parenthesis, and
 inferred type.
 
 It's like constructing a struct from scratch, with no predetermined layout.
 Blank slate.  Put anything you want in there.  And the fields don't have
 names, they only have order.
 
 In fact it's more like a block scope that can only contain data
 declarations, but without names.
 
 If you can declare those anywhere, and name, analyze and manipulate them
 anywhere, well, you have:
 
 A)  Variably-typed parameters (single-argument varargs)
 B)  Pairs/Tuples
 C)  Lists
 D)  Easy one-off structs, when you need a struct only once and don't want to
 give it a name, or give its members names.
 E)  A lot of power
 
 If you could put other things in them besides data, such as, say, types,
 well then you are approaching C++ in power.
 
 Making varargs typesafe would make printf tolerable.  I still wouldn't like
 it, but I could tolerate it.  But I am not quite clear what all would be
 involved.  I know it would require direct compiler support.
 
 Sean
 
 ----- Original Message -----
 From: "Walter" <walter digitalmars.com>
 Newsgroups: D
 Sent: Sunday, May 04, 2003 9:17 PM
 Subject: Re: String formatting stuff
 
 
 
That would be pretty cool. Any further ideas on it?

"Sean L. Palmer" <palmer.sean verizon.net> wrote in message
news:b94ebo$20n2$1 digitaldaemon.com...

printf takes a variable argument list as parameter.

Make those variable argument lists first-class, with standardized means


of
manipulation, construction, and iteration.

Would it be possible to make a printf that doesn't take a string as the
first parameter?  That is what I desire:  A free-form mass of output
capabilities that can apply however I wish without having to be known
specifically at runtime or at compile time.  One that doesn't centralize

the
processing of tokens like printf does.  One that is truly extensible by
everybody.  You wouldn't want to clutter up other peoples' printf's,

though
it'd be nice to import printf handlers from elsewhere kinda like a


module.
you could call it print.  It's like printf, but without the f.  In place

of
the f, you have completely configurable output.

throw in some parameterized field justification and precision control

which
grab hold of a value and modify how it ends up appearing, by building an
internal string of it and modifying that then transmitting it on.

You could have a "shuffler" structure and reshuffle order of its

parameters
based on some compile time switches or constants.

List processing seems like the very act of iteration.

Is this the glimmer of an answer to your iterator problems?

Sean



May 07 2003
parent "Walter" <walter digitalmars.com> writes:
Some good ideas there.

"Richard Krehbiel" <rich kastle.com> wrote in message
news:b9bilf$2uu6$1 digitaldaemon.com...
 In news://news.digitalmars.com/a7d9d2$qtv$1 digitaldaemon.com I wrote up
 a type-safe varargs proposal:


 Start with the function declaration:

 void printf(char[], PrintfParam args...)
 {
 // Function body


 "type args..." is like "type args[]" but signals that the compiler
 should collect up the arguments into the array. "type... args" should be
 a synonym of "type args..." just as "type[] array" is the same as "type
 array[]". The body of this function treats args as if it were a regular
 dynamic array, because it is.

 When a user codes:
      char[] name = "Cecil";
      printf("My name is %s\n", name);

 ..the compiler does the equivalent of this:

     PrintfParms[] _t;
     _t[0] = new PrintfParms(name);
     printf("My name is %s\n", _t);

 Rules:

      Each function argument must be implicitly compatible with the
 argument type; else,

      Each argument must be convertible to the argument type via the
 type's constructor; else,

      The argument's not valid and the compiler prints an error.

 Only the final parameter to a function can be varargs, just like C.

 I like this better than the universal VARIANT type that VB uses, since
 that way allows programmers to pass types that the function doesn't
 expect, and/or requires the called function to expect every type.  The
 argument type only needs constructors for types it can deal with.

 You can't make a varargs function in C which is allowed to take zero
 arguments.  But with this method, you can:  void NoArgs(Type args...)
 could be called with no arguments, and would receive a zero-length array.

 "<type> args..." is implicitly compatible with "<type> args[]" and, as
 such, can be passed around between functions, like C's va_list can.  But
 it's even better: you can write code to construct the a "<type> args[]",
 but you *can't* construct a va_list in C except by calling a varargs
 function.

May 09 2003
prev sibling parent reply Helmut Leitner <helmut.leitner chello.at> writes:
"Sean L. Palmer" wrote:
 
 printf takes a variable argument list as parameter.
 
 Make those variable argument lists first-class, with standardized means of
 manipulation, construction, and iteration.
 
 Would it be possible to make a printf that doesn't take a string as the
 first parameter?  That is what I desire:  A free-form mass of output
 capabilities that can apply however I wish without having to be known
 specifically at runtime or at compile time.  One that doesn't centralize the
 processing of tokens like printf does.  One that is truly extensible by
 everybody.  You wouldn't want to clutter up other peoples' printf's, though
 it'd be nice to import printf handlers from elsewhere kinda like a module.
 
 you could call it print.  It's like printf, but without the f.  In place of
 the f, you have completely configurable output.

I don't quite understand but I think that Venus does a lot of it. It contains (in the type module) a type pointer infomation structure that is used to decorate a primitive data type parameter struct TypeMethods { uint (*hash)(void *p); int (*size)(); int (*equ )(void *p1,void *p2); int (*cmp )(void *p1,void *p2); void (*swap)(void *p1,void *p2); int (*gets)(void *p1,char *buf); int (*getf)(void *p1,char *buf,int w,int d,int opt); } struct Tpi { void *pv; TypeMethods *ptm; } This is given for existing types, but you can extend this system for new types as well. This is the method how the parameter is wrappet Tpi TypeRetTpi(inout cdouble t) { Tpi ret; ret.pv=&t; ret.ptm= &cdouble_Methods; return ret; } This is the generic formated PrintLineFmt void PrintLineFmt(Tpi tpi,int w,int d,int opt) { char buf[80]; int n=(*tpi.ptm.getf)(tpi.pv,buf,w,d,opt); printf("%.*s\n",n,(char *)buf); } This is how it is made available for a single type (always a one-line wrapper that hopefully will be optimized away): void PrintLineFmt(cdouble t,int w,int d,int opt) { PrintLineFmt(TypeRetTpi(t),w,d,opt); } This is the current cdouble getf Function int cdouble_getf(cdouble *p,char *buf,int w,int d,int opt) { return sprintf(buf,"%*.*f + %*.*fi",w,d,(*p).re,w,d,(*p).im); } that does the work. The opt parameter is for extensions. If you want to change how cdouble prints, just do a int my_cdouble_getf(cdouble *p,char *buf,int w,int d,int opt) { return sprintf(buf,"(%*.*f %*.*f)",w,d,(*p).re,w,d,(*p).im); } cdouble_Methods.getf=my_cdouble_getf; If you want to add a new type: - provide or select the methods into mytype_Methods - copy/change to TypeRetTpi(inout mytype t) - add the interface functions one-liners (Print, StrCat) I've tried to make this efficient. There is no object construction needed and the wrapping function should be optimized away. -- Helmut Leitner leitner hls.via.at Graz, Austria www.hls-software.com
May 04 2003
parent reply "Sean L. Palmer" <palmer.sean verizon.net> writes:
So I have to provide all those functions (including gets?) just to get
something to print out?  It seems a bit cumbersome.  This might get a bit
better once D's builtin typeinfo's improve.

The fact that you have to override both Print and StrCat indicates that
something is amiss in the design.  What about fprintf?  What if I want to
print into a stream or i/o device of my own design?  What if I want to print
into a socket or mailslot or named pipe?  How do I do all that without
having a proliferation of functions?

Your wrappers may be efficient, but they're still wrapping sprintf, which is
a very weighty function.

C++ iostreams got it right.  They totally separate the stream buffer/device
from the stream formatting/insertion/extraction.  That way is so much more
flexible.

Sean

"Helmut Leitner" <helmut.leitner chello.at> wrote in message
news:3EB5FF0C.A10643E2 chello.at...
 "Sean L. Palmer" wrote:
 printf takes a variable argument list as parameter.

 Make those variable argument lists first-class, with standardized means


 manipulation, construction, and iteration.

 Would it be possible to make a printf that doesn't take a string as the
 first parameter?  That is what I desire:  A free-form mass of output
 capabilities that can apply however I wish without having to be known
 specifically at runtime or at compile time.  One that doesn't centralize


 processing of tokens like printf does.  One that is truly extensible by
 everybody.  You wouldn't want to clutter up other peoples' printf's,


 it'd be nice to import printf handlers from elsewhere kinda like a


 you could call it print.  It's like printf, but without the f.  In place


 the f, you have completely configurable output.

I don't quite understand but I think that Venus does a lot of it. It contains (in the type module) a type pointer infomation structure that is used to decorate a primitive data type parameter struct TypeMethods { uint (*hash)(void *p); int (*size)(); int (*equ )(void *p1,void *p2); int (*cmp )(void *p1,void *p2); void (*swap)(void *p1,void *p2); int (*gets)(void *p1,char *buf); int (*getf)(void *p1,char *buf,int w,int d,int opt); } struct Tpi { void *pv; TypeMethods *ptm; } This is given for existing types, but you can extend this system for new types as well. This is the method how the parameter is wrappet Tpi TypeRetTpi(inout cdouble t) { Tpi ret; ret.pv=&t; ret.ptm= &cdouble_Methods; return ret; } This is the generic formated PrintLineFmt void PrintLineFmt(Tpi tpi,int w,int d,int opt) { char buf[80]; int n=(*tpi.ptm.getf)(tpi.pv,buf,w,d,opt); printf("%.*s\n",n,(char *)buf); } This is how it is made available for a single type (always a one-line

 hopefully will be optimized away):

   void PrintLineFmt(cdouble t,int w,int d,int opt) {

 This is the current cdouble getf Function

   int cdouble_getf(cdouble *p,char *buf,int w,int d,int opt)
   {
     return sprintf(buf,"%*.*f + %*.*fi",w,d,(*p).re,w,d,(*p).im);
   }

 that does the work. The opt parameter is for extensions.

 If you want to change how cdouble prints, just do a

   int my_cdouble_getf(cdouble *p,char *buf,int w,int d,int opt)
   {
     return sprintf(buf,"(%*.*f %*.*f)",w,d,(*p).re,w,d,(*p).im);
   }

   cdouble_Methods.getf=my_cdouble_getf;

 If you want to add a new type:
   - provide or select the methods into mytype_Methods
   - copy/change to TypeRetTpi(inout mytype t)
   - add the interface functions one-liners (Print, StrCat)

 I've tried to make this efficient. There is no object construction
 needed and the wrapping function should be optimized away.

 --
 Helmut Leitner    leitner hls.via.at
 Graz, Austria   www.hls-software.com

May 05 2003
parent reply Helmut Leitner <helmut.leitner chello.at> writes:
"Sean L. Palmer" wrote:
 
 So I have to provide all those functions (including gets?) just to get
 something to print out?  It seems a bit cumbersome.  

It is cumbersome.
 This might get a bit
 better once D's builtin typeinfo's improve.

I did it because it shows why type abstraction is needed and what it has to replace.
 The fact that you have to override both Print and StrCat indicates that
 something is amiss in the design.  What about fprintf?  What if I want to
 print into a stream or i/o device of my own design? 

I'm not a lover of this Java stuff. Once you start it, It's hard to get it perfectly right. Currently there is a heavy Stream class in Phobos. But to have the kind of extensibility you are looking for, a Stream should maybe be a lightweight interface. One could then have the Console as a redirectable default stream and one could implement it on any object without inheriting from the Stream class.
 What if I want to print
 into a socket or mailslot or named pipe?  How do I do all that without
 having a proliferation of functions?

No, these are only meant for primitive types and they will surely be replaced by some internal mechanism sooner or later. On the other hand I can't see a difference between an ugly proliferation of functions and the typical ugly proliferation of classes and methods.
 Your wrappers may be efficient, but they're still wrapping sprintf, which is
 a very weighty function.

One could replace it by basic functions. I didn't because I would have had to write a lot of code for this. My main goal was to have a simple way to write interfaces that work with any primitive type. BTW sprintf is weighty but also efficient. If you don't ban it completely from your application you will carry its weight around. But if it's there, why not use it?
 C++ iostreams got it right.  They totally separate the stream buffer/device
 from the stream formatting/insertion/extraction.  That way is so much more
 flexible.

But this IO is very costly and adds a lot to the C++ bloat. It will be interesting to see how D can handle this. -- Helmut Leitner leitner hls.via.at Graz, Austria www.hls-software.com
May 05 2003
next sibling parent reply "Sean L. Palmer" <palmer.sean verizon.net> writes:
How about this:

If you declare a list, the compiler knows exactly what's in it because it
parsed it and used type inference.

But if you pass that list to a variable argument function, the compiler must
supply enough type info that the function knows what's in the list.

The compiler could auto-generate this parallel list of type info's.

Once the function has this list, and the corresponding type info's, (which
should be wrapped transparently into one structure, the variable argument
list) it can iterate thru the list and dispatch based on the type info to
whatever registered functions it has for the type.

You could register any type (think:  formatter functions)

If you want real generic support you want a way to auto-register types.

This is where an extension to the overloading mechanism would come in.

Overload the parameters with *runtime dispatch*.

That means if you call a function on a type that is unknown at compile time,
it figures out what type it is at runtime and calls the appropriate
functions (think:  switch/call or some kind of map of function pointers).

Then just by providing a global overload for "write into stream" you could
get any class to be able to be written into any stream.

void write(stream s, int t) { s.write(t.tostring()); }
void write(stream s, string t) { s.write(t); }
void write(stream s, mytype t) { s.write(t.tostring()); }

void print(... args)
{
    for(x in args)
    {
        write(consoleoutstream, x); // runtime dispatch on type of x
    }
}

int main()
{
    print(1, "+", 2, "=", 1+2);
    mytype a;
    print("a is", a);
    return 1;
}

This is totally analogous to the way printf works, but modernized and *type
safe*.  And if varargs wasn't just for args, but was yet another basic type,
compatible with user-defined lists, it could prove extremely useful in other
situations as well.

Think what you could do if you add this to the above:

void write<type T> (stream s, T t) { s.write(t.tostring()); }  // that's
newfangled template syntax, not D.  D's template scope would cause namespace
lookup and overloading issues

One problem might be how is the print function above (in some module A)
supposed to know about write functions declared in some other module B?
Overloading wouldn't work right.

Oh well.

Sean

"Helmut Leitner" <helmut.leitner chello.at> wrote in message
news:3EB74DD5.53F278D6 chello.at...
 "Sean L. Palmer" wrote:
 So I have to provide all those functions (including gets?) just to get
 something to print out?  It seems a bit cumbersome.

It is cumbersome.
 This might get a bit
 better once D's builtin typeinfo's improve.

I did it because it shows why type abstraction is needed and what it has to replace.
 The fact that you have to override both Print and StrCat indicates that
 something is amiss in the design.  What about fprintf?  What if I want


 print into a stream or i/o device of my own design?

I'm not a lover of this Java stuff. Once you start it, It's hard to get it perfectly right. Currently there is a heavy Stream class in Phobos. But to have the kind of extensibility you are looking for, a Stream should maybe be a lightweight interface. One could then have the Console as a redirectable default stream and one could implement it on any object without inheriting from the Stream class.
 What if I want to print
 into a socket or mailslot or named pipe?  How do I do all that without
 having a proliferation of functions?

No, these are only meant for primitive types and they will surely be replaced by some internal mechanism sooner or later. On the other hand I can't see a difference between an ugly proliferation of functions and the typical ugly proliferation of classes and methods.
 Your wrappers may be efficient, but they're still wrapping sprintf,


 a very weighty function.

One could replace it by basic functions. I didn't because I would have had to write a lot of code for this. My main goal was to have a simple way to write interfaces that work with any primitive type. BTW sprintf is weighty but also efficient. If you don't ban it completely

 your application you will carry its weight around. But if it's there, why

 use it?

 C++ iostreams got it right.  They totally separate the stream


 from the stream formatting/insertion/extraction.  That way is so much


 flexible.

But this IO is very costly and adds a lot to the C++ bloat. It will be interesting to see how D can handle this. -- Helmut Leitner leitner hls.via.at Graz, Austria www.hls-software.com

May 06 2003
next sibling parent reply "Carlos Santander B." <carlos8294 msn.com> writes:
"Sean L. Palmer" <palmer.sean verizon.net> escribió en el mensaje
news:b97q8f$27if$1 digitaldaemon.com...
| ...
|
| void write(stream s, int t) { s.write(t.tostring()); }
| void write(stream s, string t) { s.write(t); }
| void write(stream s, mytype t) { s.write(t.tostring()); }
|
| void print(... args)
| {
|     for(x in args)
|     {
|         write(consoleoutstream, x); // runtime dispatch on type of x
|     }
| }
|
| ...

The more I think about it, the more I like it. However (correct me if I'm
wrong) x needs to be declared somewhere. And that's a problem because args
could contain (following your example) int, string, or mytype. Now, how do
you declare x? You can't declare it as object, because it will complain when
there's an int, float, or whatever. That wouldn't be a problem if D did some
boxing/unboxing a la .NET (is that so or did I mix up some terms?). I mean,
if D allowed us to do:
void foo(object o) { ... }
...
int i;
foo(i);
...
Or the opposite, for instance. That would be awesome. I think there've been
arguments against it before, but now we can see where it can be useful. Even
more: I remember someone asking toString() for all the basic types. Well,
with this, and when toString() gets implemented, you could do this:
void write(stream s, object o) { s.write(o.tostring()); }
And you wouldn't need to provide any other function. I don't know if all
this is desirable or not, but at least I think it would be useful.

—————————————————————————
Carlos Santander


---
Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.476 / Virus Database: 273 - Release Date: 2003-04-24
May 06 2003
parent "Sean L. Palmer" <palmer.sean verizon.net> writes:
x would be a special case because it's an iterator used on a varargs list;
it'll have various types throughout the iteration.  Pretty much any type
that can show up there (that a valid overload exists for write, maybe) will
get its own version of the loop body, customized for that type.

Sean

"Carlos Santander B." <carlos8294 msn.com> wrote in message
news:b98dvl$2p4g$1 digitaldaemon.com...
 "Sean L. Palmer" <palmer.sean verizon.net> escribió en el mensaje
 news:b97q8f$27if$1 digitaldaemon.com...
 | ...
 |
 | void write(stream s, int t) { s.write(t.tostring()); }
 | void write(stream s, string t) { s.write(t); }
 | void write(stream s, mytype t) { s.write(t.tostring()); }
 |
 | void print(... args)
 | {
 |     for(x in args)
 |     {
 |         write(consoleoutstream, x); // runtime dispatch on type of x
 |     }
 | }
 |
 | ...

 The more I think about it, the more I like it. However (correct me if I'm
 wrong) x needs to be declared somewhere. And that's a problem because args
 could contain (following your example) int, string, or mytype. Now, how do
 you declare x? You can't declare it as object, because it will complain

 there's an int, float, or whatever. That wouldn't be a problem if D did

 boxing/unboxing a la .NET (is that so or did I mix up some terms?). I

 if D allowed us to do:
 void foo(object o) { ... }
 ...
 int i;
 foo(i);
 ...
 Or the opposite, for instance. That would be awesome. I think there've

 arguments against it before, but now we can see where it can be useful.

 more: I remember someone asking toString() for all the basic types. Well,
 with this, and when toString() gets implemented, you could do this:
 void write(stream s, object o) { s.write(o.tostring()); }
 And you wouldn't need to provide any other function. I don't know if all
 this is desirable or not, but at least I think it would be useful.

 -------------------------
 Carlos Santander


 ---
 Outgoing mail is certified Virus Free.
 Checked by AVG anti-virus system (http://www.grisoft.com).
 Version: 6.0.476 / Virus Database: 273 - Release Date: 2003-04-24

May 06 2003
prev sibling parent reply Helmut Leitner <helmut.leitner chello.at> writes:
I think you are absolutely right. 

The best of this kind is in VB (really!!!). You define a function IIRC like

  foo(int x,int y,ParamArray pa)

and you can call it this way

  foo(x,y,1,"xy",-13.5)

Within foo you can query the array size, you have the "Variant" type that
may hold any other simple type, you can query the type of each array element
and do any conversion you need...

"Sean L. Palmer" wrote:
 
 How about this:
 
 If you declare a list, the compiler knows exactly what's in it because it
 parsed it and used type inference.
 
 But if you pass that list to a variable argument function, the compiler must
 supply enough type info that the function knows what's in the list.
 
 The compiler could auto-generate this parallel list of type info's.
 
 Once the function has this list, and the corresponding type info's, (which
 should be wrapped transparently into one structure, the variable argument
 list) it can iterate thru the list and dispatch based on the type info to
 whatever registered functions it has for the type.
 
 You could register any type (think:  formatter functions)
 
 If you want real generic support you want a way to auto-register types.
 
 This is where an extension to the overloading mechanism would come in.
 
 Overload the parameters with *runtime dispatch*.
 
 That means if you call a function on a type that is unknown at compile time,
 it figures out what type it is at runtime and calls the appropriate
 functions (think:  switch/call or some kind of map of function pointers).
 
 Then just by providing a global overload for "write into stream" you could
 get any class to be able to be written into any stream.
 
 void write(stream s, int t) { s.write(t.tostring()); }
 void write(stream s, string t) { s.write(t); }
 void write(stream s, mytype t) { s.write(t.tostring()); }
 
 void print(... args)
 {
     for(x in args)
     {
         write(consoleoutstream, x); // runtime dispatch on type of x
     }
 }
 
 int main()
 {
     print(1, "+", 2, "=", 1+2);
     mytype a;
     print("a is", a);
     return 1;
 }
 
 This is totally analogous to the way printf works, but modernized and *type
 safe*.  And if varargs wasn't just for args, but was yet another basic type,
 compatible with user-defined lists, it could prove extremely useful in other
 situations as well.
 
 Think what you could do if you add this to the above:
 
 void write<type T> (stream s, T t) { s.write(t.tostring()); }  // that's
 newfangled template syntax, not D.  D's template scope would cause namespace
 lookup and overloading issues
 
 One problem might be how is the print function above (in some module A)
 supposed to know about write functions declared in some other module B?
 Overloading wouldn't work right.
 
 Oh well.
 
 Sean

-- Helmut Leitner leitner hls.via.at Graz, Austria www.hls-software.com
May 06 2003
parent reply "Sean L. Palmer" <palmer.sean verizon.net> writes:
Of course, before anyone freaks out about making D more like VB, we would
not use this all the time, but only for special situations like printf or
when it's useful.  Not everything would be done as varargs.  There'd still
be actual variables and exact parameter types if you wanted.  There'd still
be arrays of uniform type.  Just adding ordered bags of datums of mixed
types, and a bit of reflection to help figure out what's in them later.

I'm not sure I'd not rather have to specify:

foo(x, y, (1, "xy", -13.5) )

instead.  Or,

foo(x, y, [1, "xy", -13.5] )

Also Variant is kind of a nice way to write "void*" but it's kinda lame
because it's so final.

I'd rather be able to constrain the types admitted somehow so they all have
to derive off some base class or interface.  list of printables, list of
streamables, maybe.  They don't have to be all the same type or size, and
they wouldn't even really have to be references, they could be values such
as structs or ints.  for instance, list of numerics.

Sean

"Helmut Leitner" <helmut.leitner chello.at> wrote in message
news:3EB7FD0A.8350CC5A chello.at...
 I think you are absolutely right.

 The best of this kind is in VB (really!!!). You define a function IIRC

   foo(int x,int y,ParamArray pa)

 and you can call it this way

   foo(x,y,1,"xy",-13.5)

 Within foo you can query the array size, you have the "Variant" type that
 may hold any other simple type, you can query the type of each array

 and do any conversion you need...

 "Sean L. Palmer" wrote:
 How about this:

 If you declare a list, the compiler knows exactly what's in it because


 parsed it and used type inference.

 But if you pass that list to a variable argument function, the compiler


 supply enough type info that the function knows what's in the list.

 The compiler could auto-generate this parallel list of type info's.

 Once the function has this list, and the corresponding type info's,


 should be wrapped transparently into one structure, the variable


 list) it can iterate thru the list and dispatch based on the type info


 whatever registered functions it has for the type.

 You could register any type (think:  formatter functions)

 If you want real generic support you want a way to auto-register types.

 This is where an extension to the overloading mechanism would come in.

 Overload the parameters with *runtime dispatch*.

 That means if you call a function on a type that is unknown at compile


 it figures out what type it is at runtime and calls the appropriate
 functions (think:  switch/call or some kind of map of function


 Then just by providing a global overload for "write into stream" you


 get any class to be able to be written into any stream.

 void write(stream s, int t) { s.write(t.tostring()); }
 void write(stream s, string t) { s.write(t); }
 void write(stream s, mytype t) { s.write(t.tostring()); }

 void print(... args)
 {
     for(x in args)
     {
         write(consoleoutstream, x); // runtime dispatch on type of x
     }
 }

 int main()
 {
     print(1, "+", 2, "=", 1+2);
     mytype a;
     print("a is", a);
     return 1;
 }

 This is totally analogous to the way printf works, but modernized and


 safe*.  And if varargs wasn't just for args, but was yet another basic


 compatible with user-defined lists, it could prove extremely useful in


 situations as well.

 Think what you could do if you add this to the above:

 void write<type T> (stream s, T t) { s.write(t.tostring()); }  // that's
 newfangled template syntax, not D.  D's template scope would cause


 lookup and overloading issues

 One problem might be how is the print function above (in some module A)
 supposed to know about write functions declared in some other module B?
 Overloading wouldn't work right.

 Oh well.

 Sean


May 06 2003
parent reply Ilya Minkov <midiclub 8ung.at> writes:
Sean L. Palmer wrote:
 I'd rather be able to constrain the types admitted somehow so they
 all have to derive off some base class or interface.  list of
 printables, list of streamables, maybe.  They don't have to be all
 the same type or size, and they wouldn't even really have to be
 references, they could be values such as structs or ints.  for
 instance, list of numerics.

This rather seems a problem of partial OO in D. In Sather, you could simply accept $OB and then do something like: typecase some_arg when INT then #OUT + "Got Integer: " + some_arg; when FLT then #OUT + "Got Float: " + some_arg; when $STR then #OUT + "Got String: " + some_arg; end; The typecase statement tries to cast the object to diffrent types and allows to do type-dependant actions. It may also contain an else-branch. If there is no else-branch and no match is found, an exception is rased analogous to the one the D cast would cause. Please note, that INT, FLT, and such are value types - they have value semantics and are layed on the stack, as opposed to $STR and $OB - these are abstract types and are handled by reference. Only $-types have a VTable pointer. But nontheless, value types are descendants of $OB, and thus get *boxed* whenever you pass them and a reference to a abstract type is needed. BTW, you can see that you actually don't need to know a type for printing - because $OB defines a method for string conversion, like in D for reference objects. Maybe *boxing* would be a solution. But wait, hasn't the basic printf problem been solved in the DLI version of Phobos? -i. P.S. It may also be that Sather system could use a bit more abstraction - but this would be the issue of a library and not the language. I have to check this in-depth someday.
May 07 2003
parent "Martin M. Pedersen" <mmp www.moeller-pedersen.dk> writes:
"Ilya Minkov" <midiclub 8ung.at> wrote in message
news:b9brks$7sd$1 digitaldaemon.com...
 In Sather, you could simply accept $OB and then do something like:

 typecase some_arg
 when INT then
     #OUT + "Got Integer: " + some_arg;
 when FLT then
     #OUT + "Got Float: " + some_arg;
 when $STR then
     #OUT + "Got String: " + some_arg;
 end;

 The typecase statement tries to cast the object to diffrent types and
 allows to do type-dependant actions. It may also contain an else-branch.

This is much like 'instanceof' in Nice: http://nice.sourceforge.net/safety.html In D, that could be make work like this: class A { ... } class B : A { ... } void foo(A a) { if (cast(B)a) { // in this scope, 'a' is casted to B. } } The mechanism does not seem to be fully functional in Nice yet. I don't know if it causes any problems. Regards, Martin M. Pedersen
May 07 2003
prev sibling parent "Walter" <walter digitalmars.com> writes:
"Helmut Leitner" <helmut.leitner chello.at> wrote in message
news:3EB74DD5.53F278D6 chello.at...
 C++ iostreams got it right.  They totally separate the stream


 from the stream formatting/insertion/extraction.  That way is so much


 flexible.


I agree. iostreams is both bloated and slow.
May 09 2003
prev sibling parent reply Ilya Minkov <midiclub 8ung.at> writes:
Walter wrote:
 ... Me, I always thought printf should just be built in to the
 operating system, so every program shares one copy.

Microsoft compilers, as well as LCC-Win32 and MingW32 make use of this one: MSVCRT.DLL :> -i.
May 05 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Ilya Minkov" <midiclub 8ung.at> wrote in message
news:b96mc5$15eh$1 digitaldaemon.com...
 Walter wrote:
 ... Me, I always thought printf should just be built in to the
 operating system, so every program shares one copy.


 MSVCRT.DLL

That's not really building it into the operating system, it's just making a dll out of their C runtime library. The downside of that is the usual dll-hell versioning problem.
May 09 2003
parent reply Ilya Minkov <midiclub 8ung.at> writes:
Walter wrote:
 That's not really building it into the operating system, it's just
 making a dll out of their C runtime library.

And what would you call "building into an operating system"? The Windows kernel is a DLL. The whole OS is all based off DLLs.
 The downside of that is the usual dll-hell versioning problem.

I'm not intending to start a flame on DLL hell... BUT there is definately a basic functionality which you should be able to rely upon - and it is documented somewhere. And what do you care what version of DLL it is, if it does the right stuff??? Maybe some new OS would need a new version - or could run better with it than with a program-embedded runtime? It also appears to me that the DLL versioning problems are more or less in the past - since executables now have a version signature, and installer programs are not allowed to overwrite systemwide installed libraries with older ones. I see a possibility - and it is yet a compiler writer's decision whether he makes use of it or embeds his own. That's another reason why GCC version of D would be good. -i.
May 09 2003
parent "Walter" <walter digitalmars.com> writes:
"Ilya Minkov" <midiclub 8ung.at> wrote in message
news:b9gptd$pfu$1 digitaldaemon.com...
 Walter wrote:
 That's not really building it into the operating system, it's just
 making a dll out of their C runtime library.

kernel is a DLL. The whole OS is all based off DLLs.

Good point, but there is a distinction. Operating system APIs are well documented and relatively language agnostic. The MSVC runtime dll is intimately connected with MSVC. Calling the printf in it may bet (and is) heavilly dependent on undocumented MSVC startup code and other characteristics in it. To successfully call printf in it essentially means you must be calling it from code compiled with VC. This is not true for operating system APIs.
 The downside of that is the usual dll-hell versioning problem.

definately a basic functionality which you should be able to rely upon - and it is documented somewhere. And what do you care what version of DLL it is, if it does the right stuff??? Maybe some new OS would need a new version - or could run better with it than with a program-embedded

The problem is the dependency of printf on the rest of the runtime system for the C compiler, which does change.
 It also appears to me that the DLL versioning problems are more or less
 in the past - since executables now have a version signature, and
 installer programs are not allowed to overwrite systemwide installed
 libraries with older ones.

That doesn't really solve the problem, as a program may depend on the distinct behavior of an older DLL. Every time I upgrade, I pray that my apps don't break <g>.
 I see a possibility - and it is yet a compiler writer's decision whether
 he makes use of it or embeds his own. That's another reason why GCC
 version of D would be good.

May 09 2003
prev sibling parent reply Andy Friesen <andy ikagames.com> writes:
Andy Friesen wrote:
 I got this idea from boost.  Seems to work pretty nicely.  Comments/etc 
 welcome.
 
 Console.io.write(format("String: '{%}' {%} + {%} = {%}") % "A string!" % 
 5 % 3 % (5+3));

Updated. http://www.ikagames.com/andy/d/formatter.zip char[] isFalse = "IS FALSE WHEN PRECEDED BY ITS QUOTATION"; char[] str = new Formatter("\"{0}\" {0}. {1} + {2} = {3}") % isFalse % 5 % 3 % (5+3) % Formatter.end; As always, comments welcome.
Apr 01 2003
parent reply "Achilleas Margaritis" <axilmar in.gr> writes:
"Andy Friesen" <andy ikagames.com> wrote in message
news:b6d82j$2qg$1 digitaldaemon.com...
 Andy Friesen wrote:
 I got this idea from boost.  Seems to work pretty nicely.  Comments/etc
 welcome.

 Console.io.write(format("String: '{%}' {%} + {%} = {%}") % "A string!" %
 5 % 3 % (5+3));

Updated. http://www.ikagames.com/andy/d/formatter.zip char[] isFalse = "IS FALSE WHEN PRECEDED BY ITS QUOTATION"; char[] str = new Formatter("\"{0}\" {0}. {1} + {2} = {3}") % isFalse % 5 % 3 % (5+3) % Formatter.end; As always, comments welcome.

I had a ZX Spectrum back in 1985 and I could do a (in its embedded Basic): print 1, "aaaa", 2, " The quick brown fox is ", var1 which will print: 1aaaa2 The quick brown fox is 3.5 assuming of course var1 is of type real. Why can't it be so simple ?
Apr 15 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Achilleas Margaritis" <axilmar in.gr> wrote in message
news:b7h964$ub5$1 digitaldaemon.com...
 "Andy Friesen" <andy ikagames.com> wrote in message
 news:b6d82j$2qg$1 digitaldaemon.com...
 Andy Friesen wrote:
 I got this idea from boost.  Seems to work pretty nicely.



 welcome.

 Console.io.write(format("String: '{%}' {%} + {%} = {%}") % "A string!"



 5 % 3 % (5+3));

Updated. http://www.ikagames.com/andy/d/formatter.zip char[] isFalse = "IS FALSE WHEN PRECEDED BY ITS QUOTATION"; char[] str = new Formatter("\"{0}\" {0}. {1} + {2} = {3}") % isFalse % 5 % 3 % (5+3) % Formatter.end; As always, comments welcome.

I had a ZX Spectrum back in 1985 and I could do a (in its embedded Basic): print 1, "aaaa", 2, " The quick brown fox is ", var1 which will print: 1aaaa2 The quick brown fox is 3.5 assuming of course var1 is of type real. Why can't it be so simple ?

The trouble comes from if you want a %2d format, or %x format, etc., i.e. something other than the default.
May 04 2003
parent reply "Sean L. Palmer" <palmer.sean verizon.net> writes:
const string endl = "\n";
long value = result();
print(just(right, 12)(hex(value)), " is the answer", endl);

insert howevermany modifiers (such as just or hex above) here.  These could
be anything; they could be templates, whatever.  Very extensible.

Sean

"Walter" <walter digitalmars.com> wrote in message
news:b944ia$1o55$2 digitaldaemon.com...
 The trouble comes from if you want a %2d format, or %x format, etc.,  i.e.
 something other than the default.

May 04 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Sean L. Palmer" <palmer.sean verizon.net> wrote in message
news:b94ejo$20rf$1 digitaldaemon.com...
 const string endl = "\n";
 long value = result();
 print(just(right, 12)(hex(value)), " is the answer", endl);

 insert howevermany modifiers (such as just or hex above) here.  These

 be anything; they could be templates, whatever.  Very extensible.

True, but I think you'll find that a lot of bloat is generated in the calls.
May 05 2003
next sibling parent reply "Sean L. Palmer" <palmer.sean verizon.net> writes:
So you'd get:

mov ebx, [value]
lea eax, [esp+4]
mov [eax], right
mov [eax+4], 12
mov [eax+8], ebx
push eax
call print_just_int
push offset string
call print_str
push offset endl
call print_endl

instead of:

push offset formatstring // "%+12x%s%c"
push 3 // #parms
mov ebx, value
push ebx
push offset string
push 10
call printf

It's not so bad.  I can come up with examples that bend the results in favor
of streams, too, if you'd like.  It's pretty much the equivalent of using
puts/putc instead of printf, except we have to write our own conversion from
int/float to string in that case.

If you write one humongous printf, it's going to replace quite a few calls
to individual print functions.  What you're missing is that all those calls
are made up for by the gargantuan implementation of printf itself, hidden
away in the library.

If you have a huge program consisting of mostly printf's, and are optimizing
for size, printf is likely a win.  If your program deals with very little
I/O, or if that I/O needs lots of speed, streams would probably be the
better choice.

Sean

"Walter" <walter digitalmars.com> wrote in message
news:b967p2$mml$1 digitaldaemon.com...
 "Sean L. Palmer" <palmer.sean verizon.net> wrote in message
 news:b94ejo$20rf$1 digitaldaemon.com...
 const string endl = "\n";
 long value = result();
 print(just(right, 12)(hex(value)), " is the answer", endl);

 insert howevermany modifiers (such as just or hex above) here.  These

 be anything; they could be templates, whatever.  Very extensible.

True, but I think you'll find that a lot of bloat is generated in the


May 05 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Sean L. Palmer" <palmer.sean verizon.net> wrote in message
news:b97dmp$1rj1$1 digitaldaemon.com...
 If you write one humongous printf, it's going to replace quite a few calls
 to individual print functions.  What you're missing is that all those

 are made up for by the gargantuan implementation of printf itself, hidden
 away in the library.

printf actually isn't that large.
May 09 2003
parent reply "Sean L. Palmer" <palmer.sean verizon.net> writes:
But then you also have sprintf and fprintf!!  ;)

The main problems with printf are:

It's not extensible
It's not typesafe
It's not retargetable

I could care less if it generates slightly smaller code than the library
which does all of the above.  Code size, so long as it's reasonable, is not
that big of a deal.

Sean

"Walter" <walter digitalmars.com> wrote in message
news:b9gk4i$gsq$2 digitaldaemon.com...
 "Sean L. Palmer" <palmer.sean verizon.net> wrote in message
 news:b97dmp$1rj1$1 digitaldaemon.com...
 If you write one humongous printf, it's going to replace quite a few


 to individual print functions.  What you're missing is that all those

 are made up for by the gargantuan implementation of printf itself,


 away in the library.

printf actually isn't that large.

May 09 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Sean L. Palmer" <palmer.sean verizon.net> wrote in message
news:b9gn26$lqj$1 digitaldaemon.com...
 But then you also have sprintf and fprintf!!  ;)

Those are only a few bytes each. All the printf variants call the same core routine.
 The main problems with printf are:

 It's not extensible

Yup.
 It's not typesafe

I've been using printf for 20 years and this just hasn't been an issue.
 It's not retargetable

Not sure what you mean.
 I could care less if it generates slightly smaller code than the library
 which does all of the above.  Code size, so long as it's reasonable, is

 that big of a deal.

That depends on who you are! If you're doing embedded systems, code size is still a big deal.
May 09 2003
parent reply "Sean L. Palmer" <palmer.sean verizon.net> writes:
"Walter" <walter digitalmars.com> wrote in message
news:b9gpa1$ott$1 digitaldaemon.com...
 "Sean L. Palmer" <palmer.sean verizon.net> wrote in message
 news:b9gn26$lqj$1 digitaldaemon.com...
 But then you also have sprintf and fprintf!!  ;)

Those are only a few bytes each. All the printf variants call the same

 routine.

 The main problems with printf are:

 It's not extensible

Yup.

This means you can't add your own formatting commands. You can't make it handle new types.
 It's not typesafe

I've been using printf for 20 years and this just hasn't been an issue.

Lucky you. You will admit however that it is not type safe? Personal issues aside, just a simple yes or no.
 It's not retargetable

Not sure what you mean.

Meaning you can't printf to anything you want. You also have to know the size of the buffer before you call, for sprintf. This is tedious. It's another aspect of not being extensible, but on the back end. You've heard me bitching about not being able to redirect printf to OutputDebugString for a while now, haven't you? I'd use fprintf if that would work, but it doesn't. And there's no way to call the printf core without going thru sprintf, which destroys any buffering possibilities because you have to preallocate enough storage to guarantee it'll be sufficient. What if sprintf runs out of room? Oh, wait, there's snprintf. If your vendor supports it. There's no such thing as smallocprintf, but I suppose someone could figure out a way to make one. C standard library designers did *not* think of every possible use ahead of time, but there's no way we can extend it properly. That doesn't seem elegant to me. That seems really sad.
 I could care less if it generates slightly smaller code than the library
 which does all of the above.  Code size, so long as it's reasonable, is

 that big of a deal.

That depends on who you are! If you're doing embedded systems, code size

 still a big deal.

We've already established that typesafe printf could be had for the same number of bytes as printf would take. It would however require compiler support. My gcc compiler for PS/2 is so sloppy, it outputs 4 32-bit NOP's in a row all over the place, just because it feels like it, evidently. It's supposed to be an optimized build. With that kind of overhead who would notice a few extra parms pushed or a few extra calls? It's not like printf needs to be especially fast; it's either printing to screen (limited by human perception) or disk (limited by mechanical processes), so fprintf probably spends most of its time waiting on the OS to flush the buffers. It would seriously pay to concentrate on making a truly elegant, *usable* I/O foundation for D. Most of the work can be done by someone here, there are people willing to code I/O libraries, but some of the functionality needs to be in the language itself, and its early implementations. Sean
May 09 2003
next sibling parent reply Andy Friesen <andy ikagames.com> writes:
Sean L. Palmer wrote:
*snip*
The main problems with printf are:

It's not extensible

Yup.

This means you can't add your own formatting commands. You can't make it handle new types.

One could always simply add a %o command, which would assume an object reference, and use its toString method to string-ize it. voila.
It's not typesafe

I've been using printf for 20 years and this just hasn't been an issue.


This has kicked me in the pants a few times, most notably when I wanted to print out an integer to some log file or other, and used %s due to a brain-fart. blech
 Lucky you.  You will admit however that it is not type safe?  Personal
 issues aside, just a simple yes or no.
 
 
It's not retargetable

Not sure what you mean.

Meaning you can't printf to anything you want. You also have to know the size of the buffer before you call, for sprintf. This is tedious. It's another aspect of not being extensible, but on the back end.

A sprintf derivant could be coded for D to return a char[] or wchar[]. Either that or use the stream classes; they have printf methods, and can be directed around freely.
 It would seriously pay to concentrate on making a truly elegant, *usable*
 I/O foundation for D.  Most of the work can be done by someone here, there
 are people willing to code I/O libraries, but some of the functionality
 needs to be in the language itself, and its early implementations.

I rather like the monad solution, using self-reference-returning methods (or overloaded operators) to specify the data to be formatted. I'm not sure if this is the cause of C++ streams' purported bloat; if it's not, then I'm fresh out of reasons not to do it this way. :)
May 10 2003
next sibling parent reply "Carlos Santander B." <carlos8294 msn.com> writes:
"Andy Friesen" <andy ikagames.com> escribió en el mensaje
news:b9i862$23u0$1 digitaldaemon.com...
| ...
| This has kicked me in the pants a few times, most notably when I wanted
| to print out an integer to some log file or other, and used %s due to a
| brain-fart.  blech
| ...

I had a similar problem too (but with fscanf). Last year I was making a
university project in VC++. I had to read some nodes from a text file, but
at the beginning of the file I had how many nodes were. I accidently wrote
fscanf(file,"%s",&count) and continued like that. I was one day from the
dead-line and my program: 1) didn't work properly, and 2) took 10 minutes to
load! If I ran it twice, I got a "low virtual memory" message. The program
used MapObjects to load an AutoCad drawing, so I thought that could be the
reason. However, when I loaded the same drawing in VB, there was nothing
wrong. So I checked my code, there was that fatal line.
I know it's not exactly the same, but it kinda shows that, just as scanf,
printf can be dangerous sometimes.

-------------------------
Carlos Santander
"Andy Friesen" <andy ikagames.com> escribió en el mensaje
news:b9i862$23u0$1 digitaldaemon.com...
| ...
| This has kicked me in the pants a few times, most notably when I wanted
| to print out an integer to some log file or other, and used %s due to a
| brain-fart.  blech
| ...

I had a similar problem too (but with fscanf). Last year I was making a
university project in VC++. I had to read some nodes from a text file, but
at the beginning of the file I had how many nodes were. I accidently wrote
fscanf(file,"%s",&count) and continued like that. I was one day from the
dead-line and my program: 1) didn't work properly, and 2) took 10 minutes to
load! If I ran it twice, I got a "low virtual memory" message. The program
used MapObjects to load an AutoCad drawing, so I thought that could be the
reason. However, when I loaded the same drawing in VB, there was nothing
wrong. So I checked my code, there was that fatal line.
I know it's not exactly the same, but it kinda shows that, just as scanf,
printf can be dangerous sometimes.

-------------------------
Carlos Santander
May 10 2003
parent reply Helmut Leitner <leitner hls.via.at> writes:
"Carlos Santander B." wrote:
 
 "Andy Friesen" <andy ikagames.com> escribió en el mensaje
 news:b9i862$23u0$1 digitaldaemon.com...
 | ...
 | This has kicked me in the pants a few times, most notably when I wanted
 | to print out an integer to some log file or other, and used %s due to a
 | brain-fart.  blech
 | ...
 
 I had a similar problem too (but with fscanf)...

You violated one of the basic C rules: *never* use fscanf (use fgets, split according to separators, read the fields). -- Helmut Leitner leitner hls.via.at Graz, Austria www.hls-software.com
May 10 2003
next sibling parent reply "Sean L. Palmer" <palmer.sean verizon.net> writes:
What use is a function you can't use?

Sean

"Helmut Leitner" <leitner hls.via.at> wrote in message
news:3EBD1659.C0E8144F hls.via.at...
 I had a similar problem too (but with fscanf)...

You violated one of the basic C rules: *never* use fscanf (use fgets, split according to separators, read the fields).

May 10 2003
next sibling parent Helmut Leitner <helmut.leitner chello.at> writes:
"Sean L. Palmer" wrote:
 
 What use is a function you can't use?
 

Not much use. A lot of C functions are like that. There are functions that are tremendously useful while others just don't live up to their potential.
 "Helmut Leitner" <leitner hls.via.at> wrote in message
 news:3EBD1659.C0E8144F hls.via.at...
 I had a similar problem too (but with fscanf)...

You violated one of the basic C rules: *never* use fscanf (use fgets, split according to separators, read the fields).


-- Helmut Leitner leitner hls.via.at Graz, Austria www.hls-software.com
May 10 2003
prev sibling parent reply "Walter" <walter digitalmars.com> writes:
"Sean L. Palmer" <palmer.sean verizon.net> wrote in message
news:b9ji54$dil$1 digitaldaemon.com...
 What use is a function you can't use?

Support legacy code.
May 14 2003
parent "Sean L. Palmer" <palmer.sean verizon.net> writes:
Good answer!

Sean

"Walter" <walter digitalmars.com> wrote in message
news:b9v38j$30qd$3 digitaldaemon.com...
 "Sean L. Palmer" <palmer.sean verizon.net> wrote in message
 news:b9ji54$dil$1 digitaldaemon.com...
 What use is a function you can't use?

Support legacy code.

May 14 2003
prev sibling next sibling parent "Carlos Santander B." <carlos8294 msn.com> writes:
"Helmut Leitner" <leitner hls.via.at> escribió en el mensaje
news:3EBD1659.C0E8144F hls.via.at...
|
|
| "Carlos Santander B." wrote:
| >
| >
| > I had a similar problem too (but with fscanf)...
|
| You violated one of the basic C rules: *never* use fscanf
| (use fgets, split according to separators, read the fields).
|
| --
| Helmut Leitner    leitner hls.via.at
| Graz, Austria   www.hls-software.com


Now I could do that, then I couldn't. I often go for the easiest way, even
if they're not too good.

-------------------------
Carlos Santander


---
Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.478 / Virus Database: 275 - Release Date: 2003-05-06
May 10 2003
prev sibling parent reply "Walter" <walter digitalmars.com> writes:
"Helmut Leitner" <leitner hls.via.at> wrote in message
news:3EBD1659.C0E8144F hls.via.at...
 You violated one of the basic C rules: *never* use fscanf
 (use fgets, split according to separators, read the fields).

LOL. I never use either. I always read the file in one read operation, then parse it.
May 14 2003
next sibling parent reply "Sean L. Palmer" <palmer.sean verizon.net> writes:
You get into trouble with portability if you read directly into structs.  Be
careful.  And parsing takes time;  we find it to be significantly impacting
our game's load times.

Sean

"Walter" <walter digitalmars.com> wrote in message
news:b9v38j$30qd$2 digitaldaemon.com...
 "Helmut Leitner" <leitner hls.via.at> wrote in message
 news:3EBD1659.C0E8144F hls.via.at...
 You violated one of the basic C rules: *never* use fscanf
 (use fgets, split according to separators, read the fields).

LOL. I never use either. I always read the file in one read operation,

 parse it.

May 14 2003
parent "Walter" <walter digitalmars.com> writes:
I didn't mean that, I meant I read it into one array of bytes. Then I parse
or cut it up as needed.

"Sean L. Palmer" <palmer.sean verizon.net> wrote in message
news:b9v9kp$5op$1 digitaldaemon.com...
 You get into trouble with portability if you read directly into structs.

 careful.  And parsing takes time;  we find it to be significantly

 our game's load times.

 Sean

 "Walter" <walter digitalmars.com> wrote in message
 news:b9v38j$30qd$2 digitaldaemon.com...
 "Helmut Leitner" <leitner hls.via.at> wrote in message
 news:3EBD1659.C0E8144F hls.via.at...
 You violated one of the basic C rules: *never* use fscanf
 (use fgets, split according to separators, read the fields).

LOL. I never use either. I always read the file in one read operation,

 parse it.


May 15 2003
prev sibling parent reply Helmut Leitner <helmut.leitner chello.at> writes:
Walter wrote:
 
 "Helmut Leitner" <leitner hls.via.at> wrote in message
 news:3EBD1659.C0E8144F hls.via.at...
 You violated one of the basic C rules: *never* use fscanf
 (use fgets, split according to separators, read the fields).

LOL. I never use either. I always read the file in one read operation, then parse it.

That's that best way, but it's sometimes not general enough. (You can't analyze Apache access logs this way, because you don't want to burden your server with e.g. 5-50 MB of RAM usage) This is a Windows / Unix issue. Unix has so efficient text file handling that you won't win a cent reading whole files. In fact using Perl it turned out to be the slower method although it is widely used as an optimization method. If you "think client" (Windwos) you don't care about memory usage, because you own your machine and any free RAM buys you nothing, but if you "think server" (Unix) any memory or resource used by one process is lost for the other users. -- Helmut Leitner leitner hls.via.at Graz, Austria www.hls-software.com
May 14 2003
parent "Walter" <walter digitalmars.com> writes:
"Helmut Leitner" <helmut.leitner chello.at> wrote in message
news:3EC32F66.732C71E5 chello.at...
 Walter wrote:
 "Helmut Leitner" <leitner hls.via.at> wrote in message
 news:3EBD1659.C0E8144F hls.via.at...
 You violated one of the basic C rules: *never* use fscanf
 (use fgets, split according to separators, read the fields).



 parse it.

(You can't analyze Apache access logs this way, because you don't want to burden your server with e.g. 5-50 MB of RAM usage)

Not necessary - use memory mapped files!
 This is a Windows / Unix issue. Unix has so efficient text file
 handling that you won't win a cent reading whole files. In fact
 using Perl it turned out to be the slower method although it
 is widely used as an optimization method.

I can see how that can happen because if you're reading the entire file in one gulp, you cannot do any processing until the entire file is read in. If buffered, you can start working on the file while the OS anticipates you wanting the rest and reads it in. (In such cases, I'd switch to memory mapped files which brings things back to par.) In any case, I find reading the file in one operation to not only be faster, but LESS code to write and fewer errors to check for and recover from.
 If you "think client" (Windwos) you don't care about memory usage,
 because you own your machine and any free RAM buys you nothing,
 but if you "think server" (Unix) any memory or resource used by
 one process is lost for the other users.

Point taken. But I'll counter that many C programs spend a lot of time allocating memory for strings parsed out of files and then copying those strings byte by byte. I just point into the file buffer. If you're clever you can avoid making any dirty pages and get some really screaming code.
May 15 2003
prev sibling parent "Sean L. Palmer" <palmer.sean verizon.net> writes:
"Andy Friesen" <andy ikagames.com> wrote in message
news:b9i862$23u0$1 digitaldaemon.com...
 Sean L. Palmer wrote:
 This means you can't add your own formatting commands.  You can't make


 handle new types.

One could always simply add a %o command, which would assume an object reference, and use its toString method to string-ize it. voila.

But if you convert to string first, it's less efficient than putting the characters directly into the stream. What if your object has 4K or more worth of textual representation?
 Meaning you can't printf to anything you want.  You also have to know


 size of the buffer before you call, for sprintf.  This is tedious.  It's
 another aspect of not being extensible, but on the back end.

A sprintf derivant could be coded for D to return a char[] or wchar[]. Either that or use the stream classes; they have printf methods, and can be directed around freely.

That's nice. I need to look at Phobos streams again.
 I rather like the monad solution, using self-reference-returning methods
 (or overloaded operators) to specify the data to be formatted.

Operators are great for this. They don't look as ugly and they don't require parenthesis. Visually they don't get in the way as much as a method call would.
 I'm not sure if this is the cause of C++ streams' purported bloat; if
 it's not, then I'm fresh out of reasons not to do it this way. :)

Supposedly it's the individual calls to print individual things, instead of one call to print multiple things. So put your I/O in a function and call those functions multiple times. ;) Sean
May 10 2003
prev sibling parent reply "Walter" <walter digitalmars.com> writes:
"Sean L. Palmer" <palmer.sean verizon.net> wrote in message
news:b9i48s$201b$1 digitaldaemon.com...
 The main problems with printf are:
 It's not extensible


handle new types.

Up to a point, you're right. That point is if you write wrappers for your new types that convert them to strings, and then printf a string.
 It's not typesafe


issues aside, just a simple yes or no.

You are correct, it is not typesafe.
 It's not retargetable


size of the buffer before you call, for sprintf. This is tedious. It's another aspect of not being extensible, but on the back end.

Check out outbuffer.printf. I believe it handilly resolves that issue, which is a nuisance problem.
 You've heard me bitching about not being able to redirect printf to
 OutputDebugString for a while now, haven't you?  I'd use fprintf if that
 would work, but it doesn't.  And there's no way to call the printf core
 without going thru sprintf, which destroys any buffering possibilities
 because you have to preallocate enough storage to guarantee it'll be
 sufficient.  What if sprintf runs out of room?  Oh, wait, there's

 If your vendor supports it.  There's no such thing as smallocprintf, but I
 suppose someone could figure out a way to make one.

Check out outbuffer.printf! I use that (and variants of it) all the time.
 That depends on who you are! If you're doing embedded systems, code size

 still a big deal.

number of bytes as printf would take. It would however require compiler support.

I thought we established that it would cost an extra vector of types for each printf.
 My gcc compiler for PS/2 is so sloppy, it outputs 4 32-bit NOP's in a row
 all over the place, just because it feels like it, evidently.  It's

 to be an optimized build.

I won't make any excuses for that <g>.
 With that kind of overhead who would notice a few
 extra parms pushed or a few extra calls?

I would. I've been paid many times based on my ability to write small/fast code.
  It's not like printf needs to be
 especially fast;  it's either printing to screen (limited by human
 perception) or disk (limited by mechanical processes), so fprintf probably
 spends most of its time waiting on the OS to flush the buffers.

printf does need to be fast. You'd be amazed how many benchmarks are throttled by it and used (rightly or wrongly) for customer buy decisions. I've many times almost sat down and recoded the entire ugly thing in assembler. In fact, a competitor of mine did so for printf and thereby was able to cover for their poor code generation.
 It would seriously pay to concentrate on making a truly elegant, *usable*
 I/O foundation for D.  Most of the work can be done by someone here, there
 are people willing to code I/O libraries, but some of the functionality
 needs to be in the language itself, and its early implementations.

I agree. Though I think outbuffer can handle quite a bit.
May 14 2003
parent "Sean L. Palmer" <palmer.sean verizon.net> writes:
"Walter" <walter digitalmars.com> wrote in message
news:b9v38i$30qd$1 digitaldaemon.com...
 "Sean L. Palmer" <palmer.sean verizon.net> wrote in message
 news:b9i48s$201b$1 digitaldaemon.com...
 The main problems with printf are:
 It's not extensible




 handle new types.

Up to a point, you're right. That point is if you write wrappers for your new types that convert them to strings, and then printf a string.

But that's slower (as has been pointed out) since you first have to convert your type to the string, then print the string. It forces the intermediate data into memory, for one thing. But not in its final resting place, in a temporary buffer. It then has to be moved. Besides then you need a separate object.tostring() property for every type, anyway. Or is it .toString()? I forget. It wouldn't always necessarily be slower to make the string first. The CPU data cache will help alot. I don't have a firm argument here.
 It's not typesafe




 Lucky you.  You will admit however that it is not type safe?  Personal
 issues aside, just a simple yes or no.

You are correct, it is not typesafe.

I just wanted to get that on record. ;)
 It's not retargetable




 size of the buffer before you call, for sprintf.  This is tedious.  It's
 another aspect of not being extensible, but on the back end.

Check out outbuffer.printf. I believe it handilly resolves that issue,

 is a nuisance problem.

Hmm. I gotta admit to not being terribly familiar with D's standard library yet.
 You've heard me bitching about not being able to redirect printf to
 OutputDebugString for a while now, haven't you?  I'd use fprintf if that
 would work, but it doesn't.  And there's no way to call the printf core
 without going thru sprintf, which destroys any buffering possibilities
 because you have to preallocate enough storage to guarantee it'll be
 sufficient.  What if sprintf runs out of room?  Oh, wait, there's

 If your vendor supports it.  There's no such thing as smallocprintf, but


 suppose someone could figure out a way to make one.

Check out outbuffer.printf! I use that (and variants of it) all the time.

I guess I should.
 That depends on who you are! If you're doing embedded systems, code



 is
 still a big deal.

number of bytes as printf would take. It would however require compiler support.

I thought we established that it would cost an extra vector of types for each printf.

And those are two bytes each, indexing into an additional array of real pointers to typeinfo's for each type in the program, each of which is four bytes. That's competitive with printf, surely. Format specifiers are at least 2 bytes, don't forget the trailing NUL.
 With that kind of overhead who would notice a few
 extra parms pushed or a few extra calls?

I would. I've been paid many times based on my ability to write small/fast code.

And you know that 90% of the time gets spent in 10% of the code. Well, 50% or so percent of the ram gets spent on 50% of the data structures as well. If you want to save ram you may be able to get the savings elsewhere. If that's what it takes to get good semantics, ease of use, and extensibility, I'm willing to sacrifice a couple of CPU cycles or a couple of bytes. btw 80% of programmer time is dealing with 20% of the crufty codebase consisting of ugly inelegant hacks and riddled with nightmarish bugs and memory leaks. And 98.75% of statistics are bullshit. I do have one more argument: How do you put a color change into a result of a .tostring() operation? ANSI escape codes? Then you have to modify the backend processor to. Done as a mutator it merely requires a flush then a direct color change. If it's auto it could change color back when it goes out of scope.
  It's not like printf needs to be
 especially fast;  it's either printing to screen (limited by human
 perception) or disk (limited by mechanical processes), so fprintf


 spends most of its time waiting on the OS to flush the buffers.

printf does need to be fast. You'd be amazed how many benchmarks are throttled by it and used (rightly or wrongly) for customer buy decisions. I've many times almost sat down and recoded the entire ugly thing in assembler. In fact, a competitor of mine did so for printf and thereby was able to cover for their poor code generation.

Then you're surely aware of the above "statistic". ;)
 It would seriously pay to concentrate on making a truly elegant,


 I/O foundation for D.  Most of the work can be done by someone here,


 are people willing to code I/O libraries, but some of the functionality
 needs to be in the language itself, and its early implementations.

I agree. Though I think outbuffer can handle quite a bit.

Then I definitely _must_ research it. Sean
May 14 2003
prev sibling parent Richard Krehbiel <rich kastle.com> writes:
Walter wrote:
 "Sean L. Palmer" <palmer.sean verizon.net> wrote in message
 news:b94ejo$20rf$1 digitaldaemon.com...
 
const string endl = "\n";
long value = result();
print(just(right, 12)(hex(value)), " is the answer", endl);

insert howevermany modifiers (such as just or hex above) here.  These

could
be anything; they could be templates, whatever.  Very extensible.

True, but I think you'll find that a lot of bloat is generated in the calls.

I've got an odd little philosophy regarding printf. The C library printf function is like a little "virtual machine," whose "machine language" consists of the format string and the arguments. Broadly speaking, using a specialized VM gains you a lot of brevity, but has a performance const. In the case of printf, the performance lost by interpreting the format string is massively overshadowed by the cost of the external I/O operations also involved, so it's a win. I've got no problem so far. But that still leaves the fact that C language users must code printf's "machine code" themselves, which is a source of many programming errors. It sure would be nice to have some new compiler, which could create printf's machine language for me, one which would correctly match the number and types or the arguments to the format string. (Hint, hint.)
May 07 2003