December 11, 2005
This is a question I would like to put out there to all of those that support whisper syntax. Why is it preferable over writef-like syntax?

Why use something like

stdout(a)(b)(c)(d)(e)(f);

instead of

writef(a, b, c, d, e, f);

or if you are using a stream something like

stream.write(a, b, c, d, e, f);

??? To me the writef syntax is natural because it's just normal method call syntax, whereas whisper syntax is not natural at all. I can't think of a case where whisper syntax would be preferable over something as natural (and elegant imo) as that of writef.


December 11, 2005
Im just curious why its called 'Whisper', whats the story behind this? :D



December 11, 2005
JT wrote:
> Im just curious why its called 'Whisper', whats the story behind this? :D
> 

I did a quick google search and I think it has to do with the syntax of the whisper programming language.

http://tinyurl.com/9yats

December 11, 2005
"Ben Phillips" <Ben_member@pathlink.com> wrote in message news:dnhd71$2635$1@digitaldaemon.com...
> This is a question I would like to put out there to all of those that
> support
> whisper syntax. Why is it preferable over writef-like syntax?
>
> Why use something like
>
> stdout(a)(b)(c)(d)(e)(f);
>
> instead of
>
> writef(a, b, c, d, e, f);
>
> or if you are using a stream something like
>
> stream.write(a, b, c, d, e, f);
>
> ??? To me the writef syntax is natural because it's just normal method
> call
> syntax, whereas whisper syntax is not natural at all. I can't think of a
> case
> where whisper syntax would be preferable over something as natural (and
> elegant
> imo) as that of writef.

I don't think the syntax is too ugly or hard to follow, but it makes it somewhat easier to write the functions.  Consider what you'd have to do if you used variadic args:

class Something
{
 public void opCall(...)
 {
  for(uint i = 0; i < _arguments.length; i++)
  {
   if(_arguments[i] == typeid(byte))
   {
       // cast, output, use the std.stdarg.va_arg function to increment the
arg ptr
   }
   else if(_arguments[i] == typeid(ubyte))
   {
        // cast, output, use the std.stdarg.va_arg function to increment the
arg ptr
   }
   // .... for every type
  }
 }
}

This puts a lot of RTTI overhead in the opCall implementation, especially if you're writing an output stream opCall which has to support a ton of types.

Consider, then, the "Whisper" method:

class Something
{
 public Something opCall(byte b)
 {
  // output b;
  return this;
 }

 public Something opCall(ubyte b)
 {
  // output b;
  return this;
 }
}

The correct function is selected at compile time rather than having to determine the input values' types for each parameter to the function.  The only disadvantage of the Whisper method is the overhead of calling the opCalls for each parameter instead of making one call for a group of parameters, but it'd have to be tested to see if the price of RTTI testing with the single-function method would eliminate any gains made by only calling the opCall once.


December 11, 2005
The name came about from the usage of the parens (as in the way a writer uses parens).  It looks as though someone is whispering things.

Another option at the time was "psssst" ~ but that didn't quite have the same ring to it ;-)

- Kris


"JT" <JT_member@pathlink.com> wrote in message news:dnhevh$2ag6$1@digitaldaemon.com...
> Im just curious why its called 'Whisper', whats the story behind this? :D
>
>
> 


December 11, 2005
"Ben Phillips" <Ben_member@pathlink.com> wrote in message news:dnhd71$2635$1@digitaldaemon.com...
> This is a question I would like to put out there to all of those that
> support
> whisper syntax. Why is it preferable over writef-like syntax?
>
> Why use something like
>
> stdout(a)(b)(c)(d)(e)(f);
>
> instead of
>
> writef(a, b, c, d, e, f);



I'll have a go at answering this, Ben, with my personal observations. Others will no-doubt have alternative perspectives. First, I'll crib some text from a prior post:

~~~~~~~~~~~~~~~~~

Yes, that's the general idea. The mango.io package is based partly upon a set of buffered readers and writers. At their heart, the readers and writers support a chaining put/get syntax; similar to how you describe it:

class Writer {
  Writer put (int) {}
  Writer put (char[]) {}
  Writer put (dchar[]) {}
  ...
}

class Reader {
  Reader get (inout int) {}
  Reader get (inout char[]) {}
  Reader get (inout dchar[]) {}
  ...
}

These are aliased both as opCall() and opShl()/opShr(). Obviously, this
supports the C++ iostream syntax:

Writer write;
Reader read;

write << 10 << "green bottles";
read >> count >> description.

But, more to the point, it supports what we affectionately call "whisper" syntax in Mango:

 void foo (Writer write, Reader read)
{
    char[] materials;
    int    time, cost;

    write (time) (cost) (materials);
    read  (time) (cost) (materials);
}

Some  nice aspects of this particular approach are:

1) the syntax is identical for both read & write operations. The compiler takes care of providing the appropriate source or target reference. The only different is the verb used (write vs read). You can use the verbs input/output instead, if that rocks your boat :-)

2) it is thoroughly type-safe. At compile-time!

3) default arguments can be passed as part of the call.

4) it is quite efficient. DMD does a fine job optimizing this style of programming. It's faster than extracting type-info from varargs.

5) the approach supports an obvious and natural way to be explicit about
transcoding (between char/wchar/wdchar content).

6) it is flexible and highly extensible. For example, the syntax is just the same whether you're working with text or binary I/O

7) an empty set of parenthesis maps quite naturally to a "flush" operation
:-)

e.g:  write (time) (cost) (materials) ();

8) there's nothing that restricts one from using printf() syntax instead.
For example, the text oriented DisplayWriter additionally has print() and
println() methods. Stdout is an instance of DisplayWriter.

9) it becomes trivial to map a user-class to the I/O system ~ i.e.

==============
class ContractJob : IWritable, IReadable
{
    char[] materials;
    int    time, cost;

     void write (IWriter output)
    {
        output (time) (cost) (materials);
    }

     void read (IReader input)
    {
        input (time) (cost) (materials);
    }
}

ContractJob job1;
ContractJob job2;

write (job1) (job2) ();
read (job1) (job2);
===============

10) "whisper" is a cool name :-p


You can read more about Mango I/O in the source code, such as here:

http://trac.dsource.org/projects/mango/browser/trunk/mango/io/Buffer.d http://trac.dsource.org/projects/mango/browser/trunk/mango/io/Writer.d http://trac.dsource.org/projects/mango/browser/trunk/mango/io/Reader.d

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~



Now I'll try to identify a distinction. For my purposes, there are really two types of I/O in general usage ~ where one is a special case of the other.

1) raw data I/O

2) formatted, or readable, I/O; though I'll try to keep things simple by avoiding XML et. al.

Whisper syntax is all about the first instance. Through subclassing, it handles things like endian issues, class serialization, and so on.

Formatted I/O, and output in particular, is a really useful thing to have. Witness the various remarks from Walter about printf() and why it was still around in D for ages. Console output is perhaps the predominant area for such things, though files used to be written this way also. I find printf() formatting invaluable for console output also, but prefer something more robust for the long-term ~ logging APIs are one solution there. I should also note that, IMO, all the nice little formatting capabilites in printf() should actually be exposed as a cohesive and efficient set of discrete functions; for usage in areas other than console interaction. Mango.convert takes care of this by exposing each discrete function that the formatter uses. That's simply a design choice.

Anyway, I find there's a delineation between #1 & #2, but with some overlap. Of course, it would be great to blend the two camps together. Mango.io has experimented in this area by adding print() and println() methods to a writer subclass called DisplayWriter ~ which avoids some concerns such as redundant buffering.

Someone mentioned earlier that they thought Walter had "rejected" the idea of using opCall. In retrospect (after reading Justin's link), it's clear to me Walter felt that typesafe varargs were a better way to handle formatted output. I, for one, fully agree! So he added typesafe varargs, and I assume moved onto better things. Yet, formatted output is not the focus of "whisper", which is why mango.io has significant support for formatting and tokenizing *as a seperate entity* from raw I/O.

I really want to point out two things that may get lost here:

1) whisper gets compile-time type-safety applied, and is truly symmetrical in usage.

2) Strewth! it's just an I/O package! I really just can't believe all the fuss and bad feeling over this ~ it's like mango.io were holding someone's child for randsom!  Everyone, get over it :-) And, if you like the notions, then please lend a hand with the Mango project ~ the more the merrier ;-)

(*cough*)


So, in summary, mango.io leverages both approaches. It's horses-for-courses all over again. Does that help?

- Kris


Top | Discussion index | About this forum | D home