Boost logo

Boost :

From: Larry Evans (jcampbell3_at_[hidden])
Date: 2003-06-28 09:07:15


On 28 Jun 2003 01:38:14 -0700 (PDT) Daryle Walker wrote:
> On Friday, June 27, 2003, at 8:34 AM, Larry Evans wrote:
>
>> Paul A. Bristow wrote:
>
> [SNIP]

[snip]

> Was the code machine-generated (e.g. Perl script, etc.)? I was
> wondering that when I noticed that the statements end (as always) and
> _begin_ (sometimes) with semicolons (there's only one semicolon between
> consecutive statements), and empty functions still have one semicolon.
> What advantages does your style have?

Years ago, I noticed one person put all semicolons in the same column.
This lead to semicolons in a far right column's, I suppose to make it
easier to see missing semicolons. Also, years ago, another person
wrote a program to print is program formated with square blocks
indicating the nested, e.g.

   if(x==7)
   ----------------
   | a := b; |
   | if(a>c) |
   | ------------ |
   | | a := c; | |
   | | b := c; | |
   | ------------ |
   | c := 2; |
   ----------------

I just substituted the ;'s for the left |'s in the blocks closely
approximated what both these people intended:

   ; a := b
   ; if(a>c)
     { a := c
     ; b := c
     ;}
   ; c := 2

This first person also put the type and identifier of his declarations
in distinct columns:

     int a ;
     very_long_typename b ;

the purpose being, I guess, to easily find the identifier or type. I
thought finding the identifier was most important so I thought why not
put it in a prominent place, at the left hand margin. Hence:

       int
     a ;
       very_long_typename
     b ;

This left the problem of semicolons. In the case of declarations,
this sometimes serves as a "placeholder" for the definition of a
method; hence, the "logical" location for it is the place where the
definition would go. Hence:

       int
     a
       ;
       very_long_typename
     b
       ;
       char
     a_not_yet_defined_function(void)
       ;

This also has the distinct advantage of enabling cut-and-paste when
defining the function:

       char
   class_owning_following_function::
     a_not_yet_defined_function(void)
       { ...
       ;}

Now what about beginning elements in argument list with the character
"," ? Well this is just an extension of the ";" usage. If you think
about the parse-tree, you see another reason why. Each delimiter,
either "," in case of arg list or ";" in case of statement list, is
the root to a subtree in the parse tree (similar to a cons in lisp).
Hence, putting these operators first amounts to turning the parse tree
90 degrees counter-clockwise. In addition, this method resembles a
bulleted list, where the bullets are replaced by the delimiters.

And the comments. Why:

     int
   a_function
     ( type1 arg1
     , type2 arg2
     )
     //Comments for a_function
     { //function defintion
     }

instead of:

     //Comments for a_function
     int
   a_function
     ( type1 arg1
     , type2 arg2
     )
     { //function definition
     }

I had seen comments before a function repeat the listing of arguments.
This seemed a needless duplication. If instead, the function name and
its arguments were first introduced followed by the comments
describing the function, then there would be no need for a duplicate
listing of function arguments. In addition, since the comments are a
"paraphrase" of the function definition, it makes more sense that they
should come just before that definition. It seems that this should
also make it easier for a documenter, such as synopsis, to more easily
identify which comments belong where.

>
> I'm still wondering about some of the design decisions, though.

I think there are about 4 design decisions:

   1) use unbuffered streambuf

      The reason for this is just to avoid the complication of dealing
      with buffering. It may lead to more virtual function calls, but
      I'd prefer not to do optimization until it's needed.

   2) use of {attach,detach}_ostream methods

      These methods keep the destination ostream's streambuf to the
      "head" of the pipeline of ostreambuf_decorator_abs. The head is
      the last ostreambuf_decorator_abs added to the pipeline. The
      tail is the first ostreambuf_decorator_abs added to the
      pipeline. The m_streambuf of this first ostreambuf_decorator_abs
      points to the original streambuf of the ostream passed as
      argument to the CTOR of this first ostreambuf_decorator_abs,
      which is actually an ostreambuf_decorator_con.

   3) use of ostreambuf_decorator_con to start building the pipeline

      The "pipeline" is the linked list of ostreambuf_decorator_abs's
      (The _abs suffix is for "abstract". The _con suffix is for
      "concrete". ) This is needed in order to terminate the recursion
      of the {attach,detach}_ostream methods.

      I'm not sure why I used ostreambuf_decorator_impl as a superclass
      of ostreambuf_decorator_con. I may just move the _impl code to
      the _con class body.

   4) use of fwd* methods in marg_put and ostreambuf_decorator_abs

      I wanted a way to test marg_put without having to have a
      ostreambuf_decorator_abs. There are maybe better ones. Another
      one used in the delta.tar.gz most recently uploaded to
      boost/files/col_io uses the following virtual:

       int_type
     insert_on(std::streambuf& a_sbuf)
       ;

      which may be better. I haven't decided.

> It doesn't help that it's hard to figure out the designs due to the
> unusual writing style.

OK, I'll convert it to boost style. I just thought I'd wait till it
was accepted before I took the trouble, but if people are having
trouble understanding, I can't wait.


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk