www.digitalmars.com         C & C++   DMDScript  

D - formatted output trial balloon

reply "Walter" <walter digitalmars.com> writes:
Since with () overloading class objects can now look like functions, I've
been toying with the idea of using this for formatted I/O. Here's a trial
mockup of what it might look like:

-----------------------------------------------
import std.string;
import std.c.stdio;
import std.c.stdlib;

class Stdout
{
    Stdout opCall(int i)
    {
 printf("%d", i);
 return this;
    }

    Stdout opCall(char[] format, ...)
    {
 va_list ap;
 ap = cast(va_list)&format;
 ap += format.size;
 vprintf(format, ap);
 return this;
    }

    Stdout nl()
    {
 printf("\n");
 return this;
    }
}

void main()
{  Stdout stdout = new Stdout();
    stdout("hello")(" world")(47).nl()("bar")("%06i\n", 62);
}
-------------------------------------------

(Note that it retains the power of printf!) The issue here is how the syntax
stdout("foo")("bar") looks. In C++ it would look like stdout<<"foo"<<"bar"
which I don't find appealing.
Nov 05 2003
next sibling parent reply "Walter" <walter digitalmars.com> writes:
Andy Friesen also had very close to this idea earlier. -Walter

D/17402
Nov 05 2003
parent reply Kazuhiro Inaba <Kazuhiro_member pathlink.com> writes:
Andy Friesen also had very close to this idea earlier. -Walter

D/17402

Or, C++ has type-safe 'format' library http://boost.org/libs/format/doc/format.html which cout << format("%|04| *%|=7|*\n") % 100 % "foo"; prints "0100 * foo *" and linefeed. operator % is used here. (maybe % of "%d" or "%s"... is the origin) But i prefer Andy's operator~ approach. Since ~ already has the meaning "concatination", i think it's quite natural.
Nov 06 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Kazuhiro Inaba" <Kazuhiro_member pathlink.com> wrote in message
news:bodpsg$n5e$1 digitaldaemon.com...
Andy Friesen also had very close to this idea earlier. -Walter

D/17402

Or, C++ has type-safe 'format' library http://boost.org/libs/format/doc/format.html which cout << format("%|04| *%|=7|*\n") % 100 % "foo"; prints "0100 * foo *" and linefeed. operator % is used here. (maybe % of "%d" or "%s"... is the origin) But i prefer Andy's operator~ approach. Since ~ already has the meaning "concatination", i think it's quite

Thanks for the boost link. The ~ certainly does look better. One of my problems with the format() function, though, is it creates and returns a string, which then gets output. This results in double-buffering, something I want to avoid (for efficiency reasons).
Nov 06 2003
parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
What about this syntax:

	stdout ~ "asdf" ~ ("%d", foo);

Then, the class would have multiple overloaded overloadings of the ~ 
operator.

Walter wrote:
 "Kazuhiro Inaba" <Kazuhiro_member pathlink.com> wrote in message
 news:bodpsg$n5e$1 digitaldaemon.com...
 
Andy Friesen also had very close to this idea earlier. -Walter

D/17402

Or, C++ has type-safe 'format' library http://boost.org/libs/format/doc/format.html which cout << format("%|04| *%|=7|*\n") % 100 % "foo"; prints "0100 * foo *" and linefeed. operator % is used here. (maybe % of "%d" or "%s"... is the origin) But i prefer Andy's operator~ approach. Since ~ already has the meaning "concatination", i think it's quite

natural. Thanks for the boost link. The ~ certainly does look better. One of my problems with the format() function, though, is it creates and returns a string, which then gets output. This results in double-buffering, something I want to avoid (for efficiency reasons).

Nov 06 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:boecta$1kbb$1 digitaldaemon.com...
 What about this syntax:

 stdout ~ "asdf" ~ ("%d", foo);

 Then, the class would have multiple overloaded overloadings of the ~
 operator.

Unfortunately, the way overloading works, I don't see how I could make () be a parameter list rather than a parenthesized expression.
Nov 06 2003
next sibling parent "Jan-Eric Duden" <jeduden whisset.com> writes:
tuples would help here :)

-- 
Jan-Eric Duden
"Walter" <walter digitalmars.com> wrote in message
news:boep4t$26nb$1 digitaldaemon.com...
 "Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
 news:boecta$1kbb$1 digitaldaemon.com...
 What about this syntax:

 stdout ~ "asdf" ~ ("%d", foo);

 Then, the class would have multiple overloaded overloadings of the ~
 operator.

Unfortunately, the way overloading works, I don't see how I could make ()

 a parameter list rather than a parenthesized expression.

Nov 07 2003
prev sibling parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Can you expand on this?  Is this an issue particular to your compiler 
implementation, or something else?

Walter wrote:
 "Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
 news:boecta$1kbb$1 digitaldaemon.com...
 
What about this syntax:

stdout ~ "asdf" ~ ("%d", foo);

Then, the class would have multiple overloaded overloadings of the ~
operator.

Unfortunately, the way overloading works, I don't see how I could make () be a parameter list rather than a parenthesized expression.

Nov 07 2003
parent reply "Walter" <walter digitalmars.com> writes:
In general, a~b is overloaded by looking at the types of a and the types of
b. The type of a here is Stdout. The type of b, however, is the type of foo.
That isn't going to use the overload of ().

"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:bogq3g$21fv$1 digitaldaemon.com...
 Can you expand on this?  Is this an issue particular to your compiler
 implementation, or something else?

 Walter wrote:
 "Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
 news:boecta$1kbb$1 digitaldaemon.com...

What about this syntax:

stdout ~ "asdf" ~ ("%d", foo);

Then, the class would have multiple overloaded overloadings of the ~
operator.

Unfortunately, the way overloading works, I don't see how I could make


 a parameter list rather than a parenthesized expression.


Nov 08 2003
parent Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
I'm sorry, maybe I wasn't clear in what I was suggesting.  I was 
suggesting that the following expression:
	stdout ~ ("%d", foo);
would call the following member function:
	class Stdout {
		Stdout cat(char[], int);
	}
whereas simple uses (without parens) would get mapped to single-argument 
versions of cat().  So this line:
	stdout ~ "asdf" ~ ("%d", foo);
would be exactly equivalent to
	stdout.cat("asdf").cat("%d", foo);

Russ

Walter wrote:
 In general, a~b is overloaded by looking at the types of a and the types of
 b. The type of a here is Stdout. The type of b, however, is the type of foo.
 That isn't going to use the overload of ().
 
What about this syntax:

stdout ~ "asdf" ~ ("%d", foo);




Nov 10 2003
prev sibling next sibling parent reply "Charles Sanders" <sanders-consulting comcast.net> writes:
I like it!  Im not a fan of the .nl() though it looks inconsistent, not sure
how else to handle it though.

C

"Walter" <walter digitalmars.com> wrote in message
news:boc9me$1g2b$1 digitaldaemon.com...
 Since with () overloading class objects can now look like functions, I've
 been toying with the idea of using this for formatted I/O. Here's a trial
 mockup of what it might look like:

 -----------------------------------------------
 import std.string;
 import std.c.stdio;
 import std.c.stdlib;

 class Stdout
 {
     Stdout opCall(int i)
     {
  printf("%d", i);
  return this;
     }

     Stdout opCall(char[] format, ...)
     {
  va_list ap;
  ap = cast(va_list)&format;
  ap += format.size;
  vprintf(format, ap);
  return this;
     }

     Stdout nl()
     {
  printf("\n");
  return this;
     }
 }

 void main()
 {  Stdout stdout = new Stdout();
     stdout("hello")(" world")(47).nl()("bar")("%06i\n", 62);
 }
 -------------------------------------------

 (Note that it retains the power of printf!) The issue here is how the

 stdout("foo")("bar") looks. In C++ it would look like stdout<<"foo"<<"bar"
 which I don't find appealing.

Nov 05 2003
next sibling parent "Ben Hinkle" <bhinkle4 juno.com> writes:
Note .nl() is the same as ("\n") if that's any better.

-Ben

"Charles Sanders" <sanders-consulting comcast.net> wrote in message
news:bocf1q$1o62$1 digitaldaemon.com...
 I like it!  Im not a fan of the .nl() though it looks inconsistent, not

 how else to handle it though.

 C

 "Walter" <walter digitalmars.com> wrote in message
 news:boc9me$1g2b$1 digitaldaemon.com...
 Since with () overloading class objects can now look like functions,


 been toying with the idea of using this for formatted I/O. Here's a


 mockup of what it might look like:

 -----------------------------------------------
 import std.string;
 import std.c.stdio;
 import std.c.stdlib;

 class Stdout
 {
     Stdout opCall(int i)
     {
  printf("%d", i);
  return this;
     }

     Stdout opCall(char[] format, ...)
     {
  va_list ap;
  ap = cast(va_list)&format;
  ap += format.size;
  vprintf(format, ap);
  return this;
     }

     Stdout nl()
     {
  printf("\n");
  return this;
     }
 }

 void main()
 {  Stdout stdout = new Stdout();
     stdout("hello")(" world")(47).nl()("bar")("%06i\n", 62);
 }
 -------------------------------------------

 (Note that it retains the power of printf!) The issue here is how the

 stdout("foo")("bar") looks. In C++ it would look like


 which I don't find appealing.


Nov 05 2003
prev sibling next sibling parent reply J Anderson <REMOVEanderson badmama.com.au> writes:
Charles Sanders wrote:

I like it!  Im not a fan of the .nl() though it looks inconsistent, not sure
how else to handle it though.

C
  

stdout("hello")(" world")(47)(endl)("bar")("%06i\n", 62);
Nov 05 2003
next sibling parent "Sean L. Palmer" <palmer.sean verizon.net> writes:
"J Anderson" <REMOVEanderson badmama.com.au> wrote in message
news:bocj2a$1tns$2 digitaldaemon.com...
 Charles Sanders wrote:

I like it!  Im not a fan of the .nl() though it looks inconsistent, not


how else to handle it though.

Instead of nl you could have a constant, ie endl

Yah.
 stdout("hello")(" world")(47)(endl)("bar")("%06i\n", 62);

Why on earth would you go to all the trouble to replace printf, and end up supporting the same bad technique anyway in all its untype-safe glory? That last bit should be some kind of integer formatting function or object. Sean
Nov 05 2003
prev sibling parent reply "Charles Sanders" <sanders-consulting comcast.net> writes:
But what would endl be defined as, an arbitrary number ?  How would it know
i didnt actually want to output that specific number ?

C
"J Anderson" <REMOVEanderson badmama.com.au> wrote in message
news:bocj2a$1tns$2 digitaldaemon.com...
 Charles Sanders wrote:

I like it!  Im not a fan of the .nl() though it looks inconsistent, not


how else to handle it though.

C

stdout("hello")(" world")(47)(endl)("bar")("%06i\n", 62);

Nov 05 2003
next sibling parent reply Andy Friesen <andy ikagames.com> writes:
Charles Sanders wrote:

 But what would endl be defined as, an arbitrary number ?  How would it know
 i didnt actually want to output that specific number ?
 
 C

A typedeffed value. Or some sort of unique mutator object. -- andy
Nov 05 2003
parent reply "Charles Sanders" <sanders-consulting comcast.net> writes:
Whats a mutator object ?

C

"Andy Friesen" <andy ikagames.com> wrote in message
news:bocnr5$25gn$2 digitaldaemon.com...
 Charles Sanders wrote:

 But what would endl be defined as, an arbitrary number ?  How would it


 i didnt actually want to output that specific number ?

 C

A typedeffed value. Or some sort of unique mutator object. -- andy

Nov 06 2003
parent Andy Friesen <andy ikagames.com> writes:
Charles Sanders wrote:
 Whats a mutator object ?
 
 C

err.... I think C++ calls them maniuplators. Interface StreamManipulator { void manipulate(Stream s); } class Stream { ... Stream opCall(StreamManipulator manipulator) { manipulator.manipulate(this); return this; } } Basically, it's a polymorphic way to allow an object to manipulate how the stream does things. Manpulators can be used to change how the stream formats certain types of values. So, you could do something like stdout("X is equal to ")(floatFormat(8,3))(x); Where floatFormat returns a manipulator that tells stdout how to format x. (assuming x is a float) of course, stdout could simply have an overload for opCall that accepts three arguments instead of one. opCall(float f, int space, int precision) Mutators are probably still a good idea, though, as creating them doesn't require changes to the source of the stream class. -- andy
Nov 06 2003
prev sibling next sibling parent reply J Anderson <REMOVEanderson badmama.com.au> writes:
Charles Sanders wrote:

But what would endl be defined as, an arbitrary number ?  How would it know
i didnt actually want to output that specific number ?

C
"J Anderson" <REMOVEanderson badmama.com.au> wrote in message
news:bocj2a$1tns$2 digitaldaemon.com...
  

Charles Sanders wrote:

    

I like it!  Im not a fan of the .nl() though it looks inconsistent, not
      


how else to handle it though.

C


      

stdout("hello")(" world")(47)(endl)("bar")("%06i\n", 62);


or function (endl()). -Anderson
Nov 05 2003
parent reply Roberto Mariottini <Roberto_member pathlink.com> writes:
In article <bocoep$26eh$2 digitaldaemon.com>, J Anderson says...
Charles Sanders wrote:

But what would endl be defined as, an arbitrary number ?  How would it know
i didnt actually want to output that specific number ?
[...]

I'd be defined as a constant char or constant char[] or constant char*, or function (endl()).

I suggest to create a special class Stdout.NLClass, define endl as a const Stdout.NLClass object, and define an opCall with a Stdout.NLClass parameter that does the job. Ciao
Nov 05 2003
parent reply "Matthew Wilson" <matthew-hat -stlsoft-dot.-org> writes:
I'm sorry, but I think the introduction of global variables purely for
syntactic sugaring is a slippery slope that none of us will like hitting the
bottom of.

In general, if you need global variables, your design is flawed.

"Roberto Mariottini" <Roberto_member pathlink.com> wrote in message
news:bocv12$2g8q$1 digitaldaemon.com...
 In article <bocoep$26eh$2 digitaldaemon.com>, J Anderson says...
Charles Sanders wrote:

But what would endl be defined as, an arbitrary number ?  How would it



i didnt actually want to output that specific number ?
[...]

I'd be defined as a constant char or constant char[] or constant char*, or function (endl()).

I suggest to create a special class Stdout.NLClass, define endl as a const Stdout.NLClass object, and define an opCall with a Stdout.NLClass

 does the job.

 Ciao

Nov 06 2003
parent reply "Sean L. Palmer" <palmer.sean verizon.net> writes:
I'm not buying into your dogma.

Anyway it's not a global variable, it's a global constant.  Similar to PI or
whatever.  Are you saying those are always bad too?

Sean

"Matthew Wilson" <matthew-hat -stlsoft-dot.-org> wrote in message
news:bod14n$2ka4$1 digitaldaemon.com...
 I'm sorry, but I think the introduction of global variables purely for
 syntactic sugaring is a slippery slope that none of us will like hitting

 bottom of.

 In general, if you need global variables, your design is flawed.

Nov 09 2003
parent "Matthew Wilson" <matthew-hat -stlsoft-dot.-org> writes:
 I'm not buying into your dogma.

Probably wise, as I think I had my Devil's Advocate head on in this discussion
Nov 09 2003
prev sibling parent reply Dario <Dario_member pathlink.com> writes:
Charles Sanders:
But what would endl be defined as, an arbitrary number ?  How would it know
i didnt actually want to output that specific number ?

This should work: typedef uint SpecialChar; enum: SpecialChar { endl = 0, tab = 1, ... } So endl won't be confused with uints. But we can also use this: version(linux) const char endl = '\n'; version(Win32) const char[] endl = "\r\n"; But I don't like Stdout(...)(...)(...). I'd like Stdout.print(...)(...)(...) instead, though I understand that it's harder to implement. There should be: file.print(...)(...)(...); // write formatted data file.scan(...)(...)(...); // read formatted data file.write(...)(...)(...); // write raw data file.read(...)(...)(...); // read raw data I'll try to write something that works... Dario
Nov 06 2003
parent reply Dario <Dario_member pathlink.com> writes:
Something like this will work:
Nov 06 2003
next sibling parent "Matthew Wilson" <matthew-hat -stlsoft-dot.-org> writes:
He he. That's as much counter-semantic operator overloading as I like to
see.

Bravo!


"Dario" <Dario_member pathlink.com> wrote in message
news:bodm0g$he4$1 digitaldaemon.com...
 Something like this will work:

Nov 06 2003
prev sibling parent Dario <Dario_member pathlink.com> writes:
Oops, an empty message...
I swear I wrote something in it! :-O

Something like this should work:
_
_  const char[] endl = "\r\n";
_
_  struct Write
_  {   private Stream stream;
_      Write opCall(char x) { 
_          stream.rawWrite(&x, x.size);
_          return *this;
_      }
_      Write opCall(char[] x) {
_          stream.rawWrite(x, x.length);
_          return *this;
_      }
_  }
_
_  class Stream
_  {   union
_      {   private Stream self;
_          Write write;
_      }
_      this() { self = this; }
_      abstract void rawWrite(void*, uint);
_  }
_
_  class File: Stream
_  {   HANDLE fd;
_      this(HANDLE fd) { this.fd = fd; }
_      void rawWrite(void* bf, uint sz)
_      {   uint wr;
_          WriteFile(fd, bf, sz, &wr, null);
_      }
_  }
_
_  void main()
_  {   File stdout = new File(GetStdHandle(-11));
_      stdout.write("Hello")('!')(endl);
_  }

I realize that this code looks tricky and cumbersome.
And it isn't perfect too: a reference to the stream
is kept though it shouldn't be necessary.

Notice how the const char[] endl fits well.
I guess it can be useful to write portable code too.
Dario
Nov 06 2003
prev sibling parent reply Jonathan Andrew <Jonathan_member pathlink.com> writes:
In article <bocf1q$1o62$1 digitaldaemon.com>, Charles Sanders says...
I like it!  Im not a fan of the .nl() though it looks inconsistent, not sure
how else to handle it though.

C

I agree. ("\n") seems a little cleaner to me. Also, would it make sense to declare Stdout static in stdio so you don't need to instantiate it each time? -Jon
"Walter" <walter digitalmars.com> wrote in message
news:boc9me$1g2b$1 digitaldaemon.com...
 Since with () overloading class objects can now look like functions, I've
 been toying with the idea of using this for formatted I/O. Here's a trial
 mockup of what it might look like:

 -----------------------------------------------
 import std.string;
 import std.c.stdio;
 import std.c.stdlib;

 class Stdout
 {
     Stdout opCall(int i)
     {
  printf("%d", i);
  return this;
     }

     Stdout opCall(char[] format, ...)
     {
  va_list ap;
  ap = cast(va_list)&format;
  ap += format.size;
  vprintf(format, ap);
  return this;
     }

     Stdout nl()
     {
  printf("\n");
  return this;
     }
 }

 void main()
 {  Stdout stdout = new Stdout();
     stdout("hello")(" world")(47).nl()("bar")("%06i\n", 62);
 }
 -------------------------------------------

 (Note that it retains the power of printf!) The issue here is how the

 stdout("foo")("bar") looks. In C++ it would look like stdout<<"foo"<<"bar"
 which I don't find appealing.


Nov 05 2003
parent reply "Walter" <walter digitalmars.com> writes:
"Jonathan Andrew" <Jonathan_member pathlink.com> wrote in message
news:bocl5e$21g8$1 digitaldaemon.com...
 Also, would it make sense to
 declare Stdout
 static in stdio so you don't need to instantiate it each time?

Yes, of course. There'd be an abstract class forming the base of it, then there'd be Stdout deriving from it and sending its output to the console. stdout would be some global static. There'd also be another derivation from the base class which would enable buffered output to a file, and output to a string, etc. I can make all that work, so the question is do people like the ()() approach, or does it just stink? Andy suggests using ~ instead, that certainly has an appeal, but I'm a bit concerned though about sinking into the C++ << quagmire <G>.
Nov 05 2003
next sibling parent reply Helmut Leitner <helmut.leitner wikiservice.at> writes:
Walter wrote:
 I can make all that work, so the question is do people like the ()()
 approach, or does it just stink? Andy suggests using ~ instead, that
 certainly has an appeal, but I'm a bit concerned though about sinking into
 the C++ << quagmire <G>.

I dislike both, especially the ~. If you use the ()() syntax, then it must be a general language feature, that can be used for any function, e. g. MoveTo(x1,y1); DrawTo(x2,y1)(x2,y2)(x1,y2)(x1,y1); If it is that way, it may be ok. It won't hurt, if it isn't used with io in the end. If it is only usable with opCall, then it is an ugly hack. On the other hand it doesn't solve the inefficiency problem of "C++ <<", effecitivly producing a flood of func(this,fmt[,type]) calls. And it is not searchable. And what is the advantage over: stream.print(...)(...)(...); ? Even if you do this, these are still open problems - to pass a variable number of arguments safely - to get a generic interface to pass - any arry => ArrayInfoStruct - any primitive (now "Type", should be "Prim[itive]") => PrimInfoStruct - any object, array or primitive => TypeInfoStruct It would be no good to fix the io problem without taking these into account. -- Helmut Leitner leitner hls.via.at Graz, Austria www.hls-software.com
Nov 05 2003
next sibling parent reply "Sean L. Palmer" <palmer.sean verizon.net> writes:
Any function that returns itself should work like that, but how the heck
would you specify the signature of a function that returns itself?!?

(int,int)(*)(int,int)(*)(int,int)(*)(int,int)(*)(int,int)(*)(int,int)
DrawTo(int x,int y) { Line(opx,opy,x,y); opx = x; opy = y; return DrawTo; }

It doesn't even seem that typedef will help here.

Sean

"Helmut Leitner" <helmut.leitner wikiservice.at> wrote in message
news:3FA9F16C.9DF16013 wikiservice.at...
 Walter wrote:
 I can make all that work, so the question is do people like the ()()
 approach, or does it just stink? Andy suggests using ~ instead, that
 certainly has an appeal, but I'm a bit concerned though about sinking


 the C++ << quagmire <G>.

I dislike both, especially the ~. If you use the ()() syntax, then it must be a general language feature, that can be used for any function, e. g. MoveTo(x1,y1); DrawTo(x2,y1)(x2,y2)(x1,y2)(x1,y1); If it is that way, it may be ok. It won't hurt, if it isn't used with io

 If it is only usable with opCall, then it is an ugly hack.

 On the other hand it doesn't solve the inefficiency problem of "C++ <<",
 effecitivly producing a flood of
    func(this,fmt[,type])
 calls.

 And it is not searchable.

 And what is the advantage over:
    stream.print(...)(...)(...);
 ?

 Even if you do this, these are still open problems
   - to pass a variable number of arguments safely
   - to get a generic interface to pass
        - any arry                                             =>

        - any primitive (now "Type", should be "Prim[itive]")  =>

        - any object, array or primitive                       =>

 It would be no good to fix the io problem without taking these into
 account.

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

Nov 06 2003
parent "Walter" <walter digitalmars.com> writes:
"Sean L. Palmer" <palmer.sean verizon.net> wrote in message
news:boe65h$19t4$1 digitaldaemon.com...
 Any function that returns itself should work like that, but how the heck
 would you specify the signature of a function that returns itself?!?

You can't. But you *can* make it work with a so-called function object, which is an object with the () operator overloaded. This works now in D.
Nov 08 2003
prev sibling parent reply "Walter" <walter digitalmars.com> writes:
"Helmut Leitner" <helmut.leitner wikiservice.at> wrote in message
news:3FA9F16C.9DF16013 wikiservice.at...
 Walter wrote:
 I can make all that work, so the question is do people like the ()()
 approach, or does it just stink? Andy suggests using ~ instead, that
 certainly has an appeal, but I'm a bit concerned though about sinking


 the C++ << quagmire <G>.


Ok.
 If you use the ()() syntax, then it must be a general language feature,
 that can be used for any function, e. g.

    MoveTo(x1,y1);
    DrawTo(x2,y1)(x2,y2)(x1,y2)(x1,y1);

 If it is that way, it may be ok. It won't hurt, if it isn't used with io

 If it is only usable with opCall, then it is an ugly hack.

It won't work at all with functions, but it will work with function objects (i.e. opCall).
 On the other hand it doesn't solve the inefficiency problem of "C++ <<",
 effecitivly producing a flood of
    func(this,fmt[,type])
 calls.

I'm not sure why C++'s way fares so poorly. What it won't need to do is have a specialized parser for printf's format string, which takes time.
 And it is not searchable.

It is by searching for 'stdout'.
 And what is the advantage over:
    stream.print(...)(...)(...);
 ?

()() won't work with plain old functions.
 Even if you do this, these are still open problems
   - to pass a variable number of arguments safely

Use (var1)(var2)(var3) etc.
   - to get a generic interface to pass
        - any arry                                             =>

        - any primitive (now "Type", should be "Prim[itive]")  =>

        - any object, array or primitive                       =>

 It would be no good to fix the io problem without taking these into
 account.

Yes, that needs work.
Nov 08 2003
parent "Sean L. Palmer" <palmer.sean verizon.net> writes:
"Walter" <walter digitalmars.com> wrote in message
news:bojg4f$2qpr$1 digitaldaemon.com...
 On the other hand it doesn't solve the inefficiency problem of "C++ <<",
 effecitivly producing a flood of
    func(this,fmt[,type])
 calls.

I'm not sure why C++'s way fares so poorly. What it won't need to do is

 a specialized parser for printf's format string, which takes time.

We went over a way to reduce that inefficiency at one point. We actually did measure considerable overhead in the printf string parsing, in our game at one point, the font drawing function was routing everything thru sprintf. The signature of the draw function was: void Font::Draw(Vc3, Color, char const*, ...); When we changed Font().Draw(Vc3(40,50), Color::red, "My big long string"); to: Font().Draw(Vc3(40,50), Color::red, "%s", "My big long string"); we got a huge savings. Sean
Nov 09 2003
prev sibling parent reply "Matthew Wilson" <matthew-hat -stlsoft-dot.-org> writes:
"Walter" <walter digitalmars.com> wrote in message
news:bocp61$27of$1 digitaldaemon.com...
 "Jonathan Andrew" <Jonathan_member pathlink.com> wrote in message
 news:bocl5e$21g8$1 digitaldaemon.com...
 Also, would it make sense to
 declare Stdout
 static in stdio so you don't need to instantiate it each time?

Yes, of course. There'd be an abstract class forming the base of it, then there'd be Stdout deriving from it and sending its output to the console. stdout would be some global static. There'd also be another derivation

 the base class which would enable buffered output to a file, and output to

 string, etc.

 I can make all that work, so the question is do people like the ()()
 approach, or does it just stink? Andy suggests using ~ instead, that
 certainly has an appeal, but I'm a bit concerned though about sinking into
 the C++ << quagmire <G>.

It's ugly, but at least it's not (mis)using operators. I take it that the reason you want to use it is because it will do an atomic write with a result of all the individual expressions?
Nov 05 2003
parent "Walter" <walter digitalmars.com> writes:
"Matthew Wilson" <matthew-hat -stlsoft-dot.-org> wrote in message
news:bocre8$2avm$1 digitaldaemon.com...
 I take it that the reason you want to use it is because it will do an

 write with a result of all the individual expressions?

I like it because it can work without double buffering of the intermediate results. It can be as efficient as printf().
Nov 08 2003
prev sibling next sibling parent reply Andy Friesen <andy ikagames.com> writes:
Walter wrote:

 Since with () overloading class objects can now look like functions, I've
 been toying with the idea of using this for formatted I/O. Here's a trial
 mockup of what it might look like:
 
 [...]

 (Note that it retains the power of printf!) The issue here is how the syntax
 stdout("foo")("bar") looks. In C++ it would look like stdout<<"foo"<<"bar"
 which I don't find appealing.

I think () is a bit too busy. '~' may be better, since it's a lot less hoggish in terms of eyeball-space. Plus, D already uses it to indicate concatenation. stdout ~ "Hello " ~ "world" ~ 47 ~ endl ~ "bar" ~ format("%06i\n", 62); -- andy
Nov 05 2003
next sibling parent J Anderson <REMOVEanderson badmama.com.au> writes:
Andy Friesen wrote:

 [snip]

 I think () is a bit too busy.  '~' may be better, since it's a lot 
 less hoggish in terms of eyeball-space.  Plus, D already uses it to 
 indicate concatenation.

 stdout ~ "Hello " ~ "world" ~ 47 ~ endl ~ "bar" ~ format("%06i\n", 62);

  -- andy

you've got bidirectional streams how would that be handled?
Nov 05 2003
prev sibling parent reply "Matthew Wilson" <matthew-hat -stlsoft-dot.-org> writes:
More operating overloading gunk. Hate it hate it hate it. Once again the
evil zombie iostreams are sent to plague us, just wearing another head

Gilbert Grump



"Andy Friesen" <andy ikagames.com> wrote in message
news:bocnlc$25gn$1 digitaldaemon.com...
 Walter wrote:

 Since with () overloading class objects can now look like functions,


 been toying with the idea of using this for formatted I/O. Here's a


 mockup of what it might look like:

 [...]

 (Note that it retains the power of printf!) The issue here is how the


 stdout("foo")("bar") looks. In C++ it would look like


 which I don't find appealing.

I think () is a bit too busy. '~' may be better, since it's a lot less hoggish in terms of eyeball-space. Plus, D already uses it to indicate concatenation. stdout ~ "Hello " ~ "world" ~ 47 ~ endl ~ "bar" ~ format("%06i\n", 62); -- andy

Nov 05 2003
next sibling parent reply Andy Friesen <andy ikagames.com> writes:
Matthew Wilson wrote:
 More operating overloading gunk. Hate it hate it hate it. Once again the
 evil zombie iostreams are sent to plague us, just wearing another head
 
 Gilbert Grump

Yup. But the reason I use printf instead of std::stringstream isn't any asthetic aversion to using << to indicate redirection. It's not because I think it's cryptic either. I've never known stream twiddling to ever reach that sort of complexity, and I've never needed to do bit shifting in the middle of stream in/output. I simply don't like how verbose things get when you start to do more complicated formatting. It's a pain to type and look at. I don't think that operator() is any better in that regard, though I suppose it is less arbitrary in nature. (caveat: opCall can accept any number of arguments; formatting could be much simpler than with any binary operator) Maybe D just needs some (completely insane) way to overload the comma operator and translate what looks like a single varargs method call into a series of monadic calls. Maybe not. -- andy
Nov 06 2003
parent reply Hauke Duden <H.NS.Duden gmx.net> writes:
Andy Friesen wrote:
 Maybe D just needs some (completely insane) way to overload the comma 
 operator and translate what looks like a single varargs method call into 
 a series of monadic calls.  Maybe not.

Maybe D only needs a way to pass a variable number of arguments in a type-safe way. That would solve all problems of printf, since printf could always find out what was actually passed to it. Since D objects are always passed by reference only this problem is actually a little easier to solve than in C++. Howsabout the following: void print(char[] formatstring, vararglist args ); vararglist would be a special internal type that the compiler recognizes. Instead of just pushing all arguments onto the stack the compiler internally creates an array of structs of the following form (the implementation should probably be hidden from the programmer): struct vararg { int type; //type-info pointer?? TYPE arg; }; type could be a special value indicating whether it is a simple type (int, double, etc.) or an object reference. The class of the object would not have to be included, since objects in D already have runtime type information. The only problem I see with this are structs and pointers to structs. Does the compiler automatically generate some kind of typeinfo structure for each struct? If it does then vararg could simply include a pointer to that typeinfo and the called function could find out what kind of struct was passed. Another alternative, of course, would be to not allow structs to be passed to such a function. Anyway, provided that the struct problem is solved somehow then on the called side everything could be typesafe. A vararglist object could behave like some kind of iterator or cursor: void print(char[] formatstring, vararglist args) { while(args.next()) { if(args.isInt()) { int val=args.getInt(); //throws exception if //not an int or compatible type } else if(args.isObject()) { Object obj=args.getObject(); //throws an //exception if not an object } ... } } Hauke
Nov 06 2003
parent reply "Sean L. Palmer" <palmer.sean verizon.net> writes:
Why not implement it like this?:

void print(... args)
{
    foreach(v in args)
        v.print(stdout);
}

Every type then would be required to provide a print function to a stream.
There could be several such functions (auto-generated if not explicitly
provided, of course) that read and write to/from text or binary streams.
The auto-generated functions would perhaps just call the base class function
then print the new members.

Sean

"Hauke Duden" <H.NS.Duden gmx.net> wrote in message
news:bodopv$lfe$1 digitaldaemon.com...
 Andy Friesen wrote:
 Maybe D just needs some (completely insane) way to overload the comma
 operator and translate what looks like a single varargs method call into
 a series of monadic calls.  Maybe not.

Maybe D only needs a way to pass a variable number of arguments in a type-safe way. That would solve all problems of printf, since printf could always find out what was actually passed to it. Since D objects are always passed by reference only this problem is actually a little easier to solve than in C++. Howsabout the following: void print(char[] formatstring, vararglist args ); vararglist would be a special internal type that the compiler recognizes. Instead of just pushing all arguments onto the stack the compiler internally creates an array of structs of the following form (the implementation should probably be hidden from the programmer): struct vararg { int type; //type-info pointer?? TYPE arg; }; type could be a special value indicating whether it is a simple type (int, double, etc.) or an object reference. The class of the object would not have to be included, since objects in D already have runtime type information. The only problem I see with this are structs and pointers to structs. Does the compiler automatically generate some kind of typeinfo structure for each struct? If it does then vararg could simply include a pointer to that typeinfo and the called function could find out what kind of struct was passed. Another alternative, of course, would be to not allow structs to be passed to such a function. Anyway, provided that the struct problem is solved somehow then on the called side everything could be typesafe. A vararglist object could behave like some kind of iterator or cursor: void print(char[] formatstring, vararglist args) { while(args.next()) { if(args.isInt()) { int val=args.getInt(); //throws exception if //not an int or compatible type } else if(args.isObject()) { Object obj=args.getObject(); //throws an //exception if not an object } ... } } Hauke

Nov 06 2003
parent reply "Matthew Wilson" <matthew-hat -stlsoft-dot.-org> writes:
You lose atomicity of write.

"Sean L. Palmer" <palmer.sean verizon.net> wrote in message
news:boe43g$16ri$1 digitaldaemon.com...
 Why not implement it like this?:

 void print(... args)
 {
     foreach(v in args)
         v.print(stdout);
 }

 Every type then would be required to provide a print function to a stream.
 There could be several such functions (auto-generated if not explicitly
 provided, of course) that read and write to/from text or binary streams.
 The auto-generated functions would perhaps just call the base class

 then print the new members.

 Sean

 "Hauke Duden" <H.NS.Duden gmx.net> wrote in message
 news:bodopv$lfe$1 digitaldaemon.com...
 Andy Friesen wrote:
 Maybe D just needs some (completely insane) way to overload the comma
 operator and translate what looks like a single varargs method call



 a series of monadic calls.  Maybe not.

Maybe D only needs a way to pass a variable number of arguments in a type-safe way. That would solve all problems of printf, since printf could always find out what was actually passed to it. Since D objects are always passed by reference only this problem is actually a little easier to solve than in C++. Howsabout the following: void print(char[] formatstring, vararglist args ); vararglist would be a special internal type that the compiler recognizes. Instead of just pushing all arguments onto the stack the compiler internally creates an array of structs of the following form (the implementation should probably be hidden from the programmer): struct vararg { int type; //type-info pointer?? TYPE arg; }; type could be a special value indicating whether it is a simple type (int, double, etc.) or an object reference. The class of the object would not have to be included, since objects in D already have runtime type information. The only problem I see with this are structs and pointers to structs. Does the compiler automatically generate some kind of typeinfo structure for each struct? If it does then vararg could simply include a pointer to that typeinfo and the called function could find out what kind of struct was passed. Another alternative, of course, would be to not allow structs to be passed to such a function. Anyway, provided that the struct problem is solved somehow then on the called side everything could be typesafe. A vararglist object could behave like some kind of iterator or cursor: void print(char[] formatstring, vararglist args) { while(args.next()) { if(args.isInt()) { int val=args.getInt(); //throws exception if //not an int or compatible type } else if(args.isObject()) { Object obj=args.getObject(); //throws an //exception if not an object } ... } } Hauke


Nov 06 2003
parent "Sean L. Palmer" <palmer.sean verizon.net> writes:
That is not a problem.  It's "writing" directly into the stream's buffer.
The actual write happens upon buffer flushes.

Sean

"Matthew Wilson" <matthew-hat -stlsoft-dot.-org> wrote in message
news:boec1l$1j08$2 digitaldaemon.com...
 You lose atomicity of write.

 "Sean L. Palmer" <palmer.sean verizon.net> wrote in message
 news:boe43g$16ri$1 digitaldaemon.com...
 Why not implement it like this?:

 void print(... args)
 {
     foreach(v in args)
         v.print(stdout);
 }

 Every type then would be required to provide a print function to a


 There could be several such functions (auto-generated if not explicitly
 provided, of course) that read and write to/from text or binary streams.
 The auto-generated functions would perhaps just call the base class

 then print the new members.

 Sean


Nov 09 2003
prev sibling parent reply "Sean L. Palmer" <palmer.sean verizon.net> writes:
What is so evil about it?

What is more evil:

Pascal:   WriteLn("foo", ' ', bar);
C:  printf("%s%c%i\n","foo",' ',bar);
C++:  cout << "foo" << ' ' << bar << endl;
BASIC:  print "foo", " ", %bar, chr(13)

D proposal #1:  stdout("foo")(' ')(bar)(endl);
D proposal #2:  stdout ~ "foo" ~ ' ' ~ bar ~ endl;

Why would you think commas are so much better than tildes or parens?

I can see tilde being confused with the array concatenation operator.

Parens are not confusing at all, once you get used to the chained call
style.

Commas are confusing too because of the comma operator that C,C++, and D all
share.

Sean

"Matthew Wilson" <matthew-hat -stlsoft-dot.-org> wrote in message
news:bocr93$2am6$2 digitaldaemon.com...
 More operating overloading gunk. Hate it hate it hate it. Once again the
 evil zombie iostreams are sent to plague us, just wearing another head

 Gilbert Grump

Nov 06 2003
next sibling parent reply "Matthew Wilson" <matthew-hat -stlsoft-dot.-org> writes:
 What is more evil:

 Pascal:   WriteLn("foo", ' ', bar);
 C:  printf("%s%c%i\n","foo",' ',bar);
 C++:  cout << "foo" << ' ' << bar << endl;        ** This one
 BASIC:  print "foo", " ", %bar, chr(13)

 D proposal #1:  stdout("foo")(' ')(bar)(endl);
 D proposal #2:  stdout ~ "foo" ~ ' ' ~ bar ~ endl;        ** This one

 Why would you think commas are so much better than tildes or parens?

I don't
 I can see tilde being confused with the array concatenation operator.

Indeed. That is one of the objections to it
 Parens are not confusing at all, once you get used to the chained call
 style.

Indeed. That is preferable, as I think I've indicated already in this thread
 Commas are confusing too because of the comma operator that C,C++, and D

 share.

Agreed
Nov 06 2003
parent Ilya Minkov <midiclub tiscali.de> writes:
Matthew Wilson wrote:

I can see tilde being confused with the array concatenation operator.

Indeed. That is one of the objections to it

Why "confused"? It's actually the maning of it! Look. If you have an output, you are actually concatenating stuff to it. Especially if it is a file. Or even if it is a console the paradigm works well enough. It doesn't make so much sense with inputs though. I think we need something like operator : or :: on them, which could also be used for list separation? Sather uses a notation like this #OUT + "this " + 123 + " that"; It actually creates an anonymous object of class OUT and calls an add method of it. Considering that adding is Sather's way of concatenating stuff, it's basically the same idea. The operator itself simply does the output, and then passes the OUT further. -eye
Nov 07 2003
prev sibling parent "Jeandrι du Toit" <morphiax hotmail.com> writes:
What about C#'s

MessageBox.Show("NumTwo is {1} and NumOne {0} and both are {0}{1}", NumOne,
NumTwo);


"Sean L. Palmer" <palmer.sean verizon.net> wrote in message
news:boe3nb$16a7$1 digitaldaemon.com...
 What is so evil about it?

 What is more evil:

 Pascal:   WriteLn("foo", ' ', bar);
 C:  printf("%s%c%i\n","foo",' ',bar);
 C++:  cout << "foo" << ' ' << bar << endl;
 BASIC:  print "foo", " ", %bar, chr(13)

Nov 08 2003
prev sibling next sibling parent reply Roberto Mariottini <Roberto_member pathlink.com> writes:
In article <boc9me$1g2b$1 digitaldaemon.com>, Walter says...
[...]
void main()
{  Stdout stdout = new Stdout();
    stdout("hello")(" world")(47).nl()("bar")("%06i\n", 62);
}

if I understand, this would be equivalent to: stdout.opCall("hello").opCall(" world").opCall(47).nl().opCall("bar").opCall("%06i\n", 62); Right?
(Note that it retains the power of printf!)

so this: stdout("I am 50% stupid?"); generates a segmentation fault?
 The issue here is how the syntax
stdout("foo")("bar") looks. In C++ it would look like stdout<<"foo"<<"bar"
which I don't find appealing.

I like <<, I like (), I like ~ (althouhg I haven't ~ on my keyboard). Ciao
Nov 05 2003
next sibling parent reply Hauke Duden <H.NS.Duden gmx.net> writes:
Roberto Mariottini wrote:
 althouhg I haven't ~ on my keyboard).

That's important! VERY important. If ~ is not on all keyboards, then IMHO it shouldn't be a built-in operator at all. What kind of keyboard is this? Hauke
Nov 06 2003
parent reply Roberto Mariottini <Roberto_member pathlink.com> writes:
In article <bod2or$2mnk$1 digitaldaemon.com>, Hauke Duden says...
Roberto Mariottini wrote:
 althouhg I haven't ~ on my keyboard).

That's important! VERY important. If ~ is not on all keyboards, then IMHO it shouldn't be a built-in operator at all. What kind of keyboard is this?

Italian keyboard. For sure every one of the 56 millions of italians has to use the Alt-126 combination to enter a single ~. We also have no {}, but the undocumented AltGr-Shift-[ and AltGr-Shift-] cobinations fortunately work in any italian keyboard Windows driver, although I see many of my collegues using Alt-123 and Alt-125. Old italian hackers use USA keyboards, but not all employers agree to buy one for every developer. Ciao
Nov 06 2003
next sibling parent "Jan-Eric Duden" <jeduden whisset.com> writes:
OMG. I didn't think it is possible that { and } can be omitted on a keyboard
layout....

-- 
Jan-Eric Duden
"Roberto Mariottini" <Roberto_member pathlink.com> wrote in message
news:bod3l8$2o2j$1 digitaldaemon.com...
 In article <bod2or$2mnk$1 digitaldaemon.com>, Hauke Duden says...
Roberto Mariottini wrote:
 althouhg I haven't ~ on my keyboard).

That's important! VERY important. If ~ is not on all keyboards, then IMHO it shouldn't be a built-in operator at all. What kind of keyboard is this?

Italian keyboard. For sure every one of the 56 millions of italians has to use the Alt-126 combination to enter a single ~. We also have no {}, but the undocumented AltGr-Shift-[ and AltGr-Shift-] cobinations fortunately work in any italian keyboard Windows driver,

 see many of my collegues using Alt-123 and Alt-125.

 Old italian hackers use USA keyboards, but not all employers agree to buy

 for every developer.

 Ciao

Nov 06 2003
prev sibling next sibling parent Ilya Minkov <midiclub tiscali.de> writes:
I've looked at it and i find the italian keyboard very wierd. It is 
underpopulated in some spots and overpopulated in the others. Bad 
design. It also doesn't have a backquote, which is even present on 
hebrew, russian, and all other fancy keyboars i've ever seen - and which 
is requiered by some programming languages as well, most notably lisp. 
And UNIX simply doesn't work without ~.

You can use a keyboard layout editor. Under Windows i use KLM Medium:

http://www.klm.freeservers.com/

However, it costs more than a US keyboard.

Another sane solution would be a program which would be a resident and 
listen to a magic key combination, and then pastes the symbol into the 
program. Or even a widows shortcut with a hotkey to call a small program 
which would only paste a symbol into an active program...

-eye



Roberto Mariottini wrote:

 Italian keyboard.
 For sure every one of the 56 millions of italians has to use the Alt-126
 combination to enter a single ~.
 We also have no {}, but the undocumented AltGr-Shift-[ and AltGr-Shift-]
 cobinations fortunately work in any italian keyboard Windows driver, although I
 see many of my collegues using Alt-123 and Alt-125.
 
 Old italian hackers use USA keyboards, but not all employers agree to buy one
 for every developer.
 
 Ciao
 
 

Nov 06 2003
prev sibling parent reply "Walter" <walter digitalmars.com> writes:
"Roberto Mariottini" <Roberto_member pathlink.com> wrote in message
news:bod3l8$2o2j$1 digitaldaemon.com...
 Old italian hackers use USA keyboards, but not all employers agree to buy

 for every developer.

I hate to be annoying <g>, but a USA keyboard can be had for $9.99 around here. Mine cost $19.99, but that's only because I just cannot stand the oversized Enter key that substitutes for the \ key. Every time I hit \, I get Enter instead and the command gets prematurely executed, sometimes with disastrous results: rm -r foo\bar becomes: rm -r foo Argggh! Why can't these layouts be standardized? C++ tried to get around the keyboard problem by introducing digraphs. When that failed, trigraphs were introduced. That's failed too, and now there's \uxxxx, etc. (By failed I mean that I see a lot of code from all over the world, and never once have I seen any code outside of a test suite that used digraphs, trigraphs, or \u or \U.) The C/C++ experiments with this show that there isn't a known decent solution. What I do to input funky characters is cut & paste them from a palette of them.
Feb 20 2004
next sibling parent Vathix <vathix dprogramming.com> writes:
 I hate to be annoying <g>, but a USA keyboard can be had for $9.99 around
 here. Mine cost $19.99, but that's only because I just cannot stand the
 oversized Enter key that substitutes for the \ key. Every time I hit \, I
 get Enter instead and the command gets prematurely executed, sometimes with
 disastrous results:

I have that large Enter. What used to bug me is backspace being smaller and me constantly bumping the insert key; that is, until I pulled the key out :D -- Christopher E. Miller www.dprogramming.com irc.dprogramming.com #D
Feb 21 2004
prev sibling parent "Ben Hinkle" <bhinkle4 juno.com> writes:
| What I do to input funky characters is cut & paste them from a
| palette of them.

I know what you mean - the old Mac's MPW environment used greek
deltas (option-D) in scripts for line-continuation. There were
a few times when I found myself editing a script on a wacky
keyboard and could only wrap lines by cutting and pasting these
darn deltas from somewhere else. MPW loved that option key.

-Ben
Feb 21 2004
prev sibling parent Roberto Mariottini <Roberto_member pathlink.com> writes:
Hi,
the following example shows why you can't have only one 

Stdout opCall(char[] format, ...)

to handle all strings output, but you must have one opCall with only one string
as parameter.

Works with:
Digital Mars Compiler Version 8.29n
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8804 for 80x86

It doesn't work well with Borland compiler, gcc generates a segfault.

------------------------test.c----------------------------
#include <stdio.h>

char *s = "%%% stupid, not stupid %%%";

int f(char *m)
{
return m[15] = 0;
}

int main()
{
char *p = s+ 2;
f(p);
printf("I am 100% sane at all.\n");

return 0;
}
------------------------test.c----------------------------

Ciao
Nov 07 2003
prev sibling next sibling parent reply "Ben Hinkle" <bhinkle4 juno.com> writes:
This got me thinking about message chaining in Object C and SmallTalk (or
message cascading...)
Maybe a whole new syntax could help and possibly replace printf and ~.
Something like

  stdout.printf["hello", " world", 47, "\nbar", ("%06i\n", 62)];
  string.cat["a", "bc", 47, "def"];

would turn into

  stdout.printf("hello").printf("
world").printf(47).printf("\nbar").printf("%06i\n", 62);
  string.cat("a").cat("bc").cat(47).cat("def");

I haven't thought about if this syntax conflicts with anything else or is
implementable ;-)
-Ben

"Walter" <walter digitalmars.com> wrote in message
news:boc9me$1g2b$1 digitaldaemon.com...
 Since with () overloading class objects can now look like functions, I've
 been toying with the idea of using this for formatted I/O. Here's a trial
 mockup of what it might look like:

 -----------------------------------------------
 import std.string;
 import std.c.stdio;
 import std.c.stdlib;

 class Stdout
 {
     Stdout opCall(int i)
     {
  printf("%d", i);
  return this;
     }

     Stdout opCall(char[] format, ...)
     {
  va_list ap;
  ap = cast(va_list)&format;
  ap += format.size;
  vprintf(format, ap);
  return this;
     }

     Stdout nl()
     {
  printf("\n");
  return this;
     }
 }

 void main()
 {  Stdout stdout = new Stdout();
     stdout("hello")(" world")(47).nl()("bar")("%06i\n", 62);
 }
 -------------------------------------------

 (Note that it retains the power of printf!) The issue here is how the

 stdout("foo")("bar") looks. In C++ it would look like stdout<<"foo"<<"bar"
 which I don't find appealing.

Nov 06 2003
parent reply "Matthew Wilson" <matthew-hat -stlsoft-dot.-org> writes:
 This got me thinking about message chaining in Object C and SmallTalk (or
 message cascading...)
 Maybe a whole new syntax could help and possibly replace printf and ~.
 Something like

   stdout.printf["hello", " world", 47, "\nbar", ("%06i\n", 62)];
   string.cat["a", "bc", 47, "def"];

 would turn into

   stdout.printf("hello").printf("
 world").printf(47).printf("\nbar").printf("%06i\n", 62);
   string.cat("a").cat("bc").cat(47).cat("def");

 I haven't thought about if this syntax conflicts with anything else or is
 implementable ;-)
 -Ben

I think the point of the concatenated (not concatenating, mind you) syntax is that the write operation would be atomic, which would certainly need to be the case to system streams such as the log stream, and to process-wide streams in a multi-threaded process. If your example translates to a function that does that, by concatenating all input in a buffer, and then sending that to the requisite output stream in a single operation, then I would think it worth pursuing.
Nov 06 2003
next sibling parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Matthew Wilson wrote:
This got me thinking about message chaining in Object C and SmallTalk (or
message cascading...)
Maybe a whole new syntax could help and possibly replace printf and ~.
Something like

  stdout.printf["hello", " world", 47, "\nbar", ("%06i\n", 62)];
  string.cat["a", "bc", 47, "def"];

would turn into

  stdout.printf("hello").printf("
world").printf(47).printf("\nbar").printf("%06i\n", 62);
  string.cat("a").cat("bc").cat(47).cat("def");

I haven't thought about if this syntax conflicts with anything else or is
implementable ;-)
-Ben

I think the point of the concatenated (not concatenating, mind you) syntax is that the write operation would be atomic, which would certainly need to be the case to system streams such as the log stream, and to process-wide streams in a multi-threaded process.

printf() is not atomic, I believe. write() generally is, I think. But printf() buffers output until either the buffer fills up or you call fflush(). So why are you arguing about the atomicity of print mechanisms? If atomicity is critical, form your own buffer and then use write() directly.
Nov 06 2003
parent reply "Matthew Wilson" <matthew-hat -stlsoft-dot.-org> writes:
"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:boedmk$1l44$1 digitaldaemon.com...
 Matthew Wilson wrote:
This got me thinking about message chaining in Object C and SmallTalk



message cascading...)
Maybe a whole new syntax could help and possibly replace printf and ~.
Something like

  stdout.printf["hello", " world", 47, "\nbar", ("%06i\n", 62)];
  string.cat["a", "bc", 47, "def"];

would turn into

  stdout.printf("hello").printf("
world").printf(47).printf("\nbar").printf("%06i\n", 62);
  string.cat("a").cat("bc").cat(47).cat("def");

I haven't thought about if this syntax conflicts with anything else or



implementable ;-)
-Ben

I think the point of the concatenated (not concatenating, mind you)


 is that the write operation would be atomic, which would certainly need


 be the case to system streams such as the log stream, and to


 streams in
 a multi-threaded process.

printf() is not atomic, I believe. write() generally is, I think. But printf() buffers output until either the buffer fills up or you call fflush(). So why are you arguing about the atomicity of print mechanisms? If atomicity is critical, form your own buffer and then use write() directly.

Fair enough. My ineptly using printf as an example does not negate the point, however.
Nov 06 2003
parent reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
Matthew Wilson wrote:
 "Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
 news:boedmk$1l44$1 digitaldaemon.com...
 
Matthew Wilson wrote:

This got me thinking about message chaining in Object C and SmallTalk



(or
message cascading...)
Maybe a whole new syntax could help and possibly replace printf and ~.
Something like

 stdout.printf["hello", " world", 47, "\nbar", ("%06i\n", 62)];
 string.cat["a", "bc", 47, "def"];

would turn into

 stdout.printf("hello").printf("
world").printf(47).printf("\nbar").printf("%06i\n", 62);
 string.cat("a").cat("bc").cat(47).cat("def");

I haven't thought about if this syntax conflicts with anything else or



is
implementable ;-)
-Ben

I think the point of the concatenated (not concatenating, mind you)


syntax
is that the write operation would be atomic, which would certainly need


to
be the case to system streams such as the log stream, and to


process-wide
streams in
a multi-threaded process.

printf() is not atomic, I believe. write() generally is, I think. But printf() buffers output until either the buffer fills up or you call fflush(). So why are you arguing about the atomicity of print mechanisms? If atomicity is critical, form your own buffer and then use write() directly.

Fair enough. My ineptly using printf as an example does not negate the point, however.

I hear you, but I don't think that atomic writes are a big requirement for a general-purpose formatted I/O routine. Once the routine is in place, you can use the syntax (whatever it happens to be) to build a buffer in memory, something like: Stream str = new BufStream; str <insert the formatting syntax here>; write(file_pointer, str);
Nov 06 2003
parent reply Ilya Minkov <midiclub tiscali.de> writes:
Russ Lewis wrote:

 I hear you, but I don't think that atomic writes are a big requirement 
 for a general-purpose formatted I/O routine.  Once the routine is in 
 place, you can use the syntax (whatever it happens to be) to build a 
 buffer in memory, something like:
 
   Stream str = new BufStream;
   str <insert the formatting syntax here>;
   write(file_pointer, str);

IIRC that's what Walter wanted to avoid forcing on the user, for efficiency reasons. He wants whatever system D has to be at least as efficient as printf. Not a basic requierement for the IO system IMHO - that's what the same write is for. A basic requierement is typesafety, extensibility, and ease of use even for beginners. C++ iostreams serve these requierements wonderfully well. -eye
Nov 07 2003
parent Hauke Duden <H.NS.Duden gmx.net> writes:
Ilya Minkov wrote:
 I hear you, but I don't think that atomic writes are a big requirement 
 for a general-purpose formatted I/O routine.  Once the routine is in 
 place, you can use the syntax (whatever it happens to be) to build a 
 buffer in memory, something like:

   Stream str = new BufStream;
   str <insert the formatting syntax here>;
   write(file_pointer, str);

IIRC that's what Walter wanted to avoid forcing on the user, for efficiency reasons. He wants whatever system D has to be at least as efficient as printf. Not a basic requierement for the IO system IMHO - that's what the same write is for. A basic requierement is typesafety, extensibility, and ease of use even for beginners. C++ iostreams serve these requierements wonderfully well.

I just had an idea to create an atomic version of the proposed print with the same syntax. Couldn't the first atomicPrint call return an auto object (like the BufStream mentioned above) that itself works in the same way as the proposed StdIO object? It would accumulate the following print calls and output the resulting string when its destructor is called. Essentially this would be the same as using a temporary Stream object, except that the user would not have to create it explicitly. Not sure whether auto-objects can be returned from a function, though. My intuition tells me probably not, but I'll would have to try it out... Hauke
Nov 07 2003
prev sibling next sibling parent "Ben Hinkle" <bhinkle4 juno.com> writes:
"Matthew Wilson" <matthew-hat -stlsoft-dot.-org> wrote in message
news:boec1m$1j08$3 digitaldaemon.com...
 This got me thinking about message chaining in Object C and SmallTalk


 message cascading...)
 Maybe a whole new syntax could help and possibly replace printf and ~.
 Something like

   stdout.printf["hello", " world", 47, "\nbar", ("%06i\n", 62)];
   string.cat["a", "bc", 47, "def"];

 would turn into

   stdout.printf("hello").printf("
 world").printf(47).printf("\nbar").printf("%06i\n", 62);
   string.cat("a").cat("bc").cat(47).cat("def");

 I haven't thought about if this syntax conflicts with anything else or


 implementable ;-)
 -Ben

I think the point of the concatenated (not concatenating, mind you) syntax is that the write operation would be atomic, which would certainly need to be the case to system streams such as the log stream, and to process-wide streams in a multi-threaded process. If your example translates to a function that does that, by concatenating all input in a buffer, and then sending that to the requisite output

 in a single operation, then I would think it worth pursuing.

I hadn't thought about that. Reading my post again (aside from the fact that I can't spell "Objective" before my first cup of coffee) I also see I was assuming strings were class objects and not plain arrays. I'll ponder some more about the atomic stuff and about cascading non-member functions. -Ben
Nov 06 2003
prev sibling parent "Sean L. Palmer" <palmer.sean verizon.net> writes:
There are equally as many cases where you *don't* want the output to be
atomic.  It is slower to write into this temporary buffer, before sending
the final buffer to the stream, than to write directly into the stream's
buffer.  Besides, you don't usually know how big of a buffer you're going to
need before you start writing.

Streams are always buffered, right?  If so there's a nice Flush() command
somewhere.

Unbuffered streams are horribly inefficient.

Sean

"Matthew Wilson" <matthew-hat -stlsoft-dot.-org> wrote in message
news:boec1m$1j08$3 digitaldaemon.com...
 This got me thinking about message chaining in Object C and SmallTalk


 message cascading...)
 Maybe a whole new syntax could help and possibly replace printf and ~.
 Something like

   stdout.printf["hello", " world", 47, "\nbar", ("%06i\n", 62)];
   string.cat["a", "bc", 47, "def"];

 would turn into

   stdout.printf("hello").printf("
 world").printf(47).printf("\nbar").printf("%06i\n", 62);
   string.cat("a").cat("bc").cat(47).cat("def");

 I haven't thought about if this syntax conflicts with anything else or


 implementable ;-)
 -Ben

I think the point of the concatenated (not concatenating, mind you) syntax is that the write operation would be atomic, which would certainly need to be the case to system streams such as the log stream, and to process-wide streams in a multi-threaded process. If your example translates to a function that does that, by concatenating all input in a buffer, and then sending that to the requisite output

 in a single operation, then I would think it worth pursuing.

Nov 09 2003
prev sibling next sibling parent reply Patrick Down <Patrick_member pathlink.com> writes:
Why not make IO a more formal operation.

Introduce a new keyword "write"

Syntax: write object, param [,param]*;

Example:

float a = 12.4;
write stdOut,"Hello ",12,.format(4,2,a)," amount";

Any "." preceeded name is considers a function of
the object.

The object has opWrite functions.

class StdOut
{
opWrite(char[]) { }
opWrite(int) { }  
opWrite(float) { }

format(int digits,int postDigits, float value);
}

Read is handled in a similar way.

Example:

read stdIn, a, b, c;

class StdIn
{
opRead(out char[]) { }
opRead(out int) {}
//etc...
}
Nov 06 2003
parent "Sean L. Palmer" <palmer.sean verizon.net> writes:
Because typesafe varargs is useful for lots of things besides I/O.

Sean

"Patrick Down" <Patrick_member pathlink.com> wrote in message
news:boe5fs$18se$1 digitaldaemon.com...
 Why not make IO a more formal operation.

 Introduce a new keyword "write"

 Syntax: write object, param [,param]*;

Nov 09 2003
prev sibling next sibling parent "Carlos Santander B." <carlos8294 msn.com> writes:
"Walter" <walter digitalmars.com> wrote in message
news:boc9me$1g2b$1 digitaldaemon.com...
| ...
|     stdout("hello")(" world")(47).nl()("bar")("%06i\n", 62);
| ...

Personally, I don't like so many (). ~ feels a bit better. However, I agree
that true typesafe varargs would be the ideal solution for this.

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


---

Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.536 / Virus Database: 331 - Release Date: 2003-11-03
Nov 06 2003
prev sibling next sibling parent Matthias Becker <Matthias_member pathlink.com> writes:
This all doesn't help me, to output objects of my own classes, does it?
Nov 16 2003
prev sibling parent Jan Knepper <jan smartsoft.us> writes:
Walter wrote:

 (Note that it retains the power of printf!) The issue here is how the syntax
 stdout("foo")("bar") looks. In C++ it would look like stdout<<"foo"<<"bar"
 which I don't find appealing.

stdout << "foo" << "bar"; Does indeed not loop very appealing. I personally would have liked better: stdout << "foo", "bar", i, "\n", "second line", nl; Jan
Nov 16 2003