View mode: basic / threaded / horizontal-split · Log in · Help
December 11, 2005
Whisper Syntax
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
Re: Whisper Syntax
Im just curious why its called 'Whisper', whats the story behind this? :D
December 11, 2005
Re: Whisper Syntax
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
Re: Whisper Syntax
"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
Re: Whisper Syntax
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
Re: Whisper Syntax
"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