May 05, 2003
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
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 05, 2003
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 05, 2003
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
>
>
> "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
> 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 05, 2003

"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 05, 2003
"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.


May 05, 2003
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 06, 2003
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
> 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.
>
>


May 06, 2003
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
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 06, 2003
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 06, 2003

"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