Is it possible to have static inline member functions of a class?
I dont ever recall seeing "static" and "inline" together.
if so, how is it done ?
I know of inline non-static member functions, either defined within
the class or outside the class body but with "inline" keyword
Thanks
Stephen Howe
Why not?
> I dont ever recall seeing "static" and "inline" together.
With member functions you rarely spell "inline", as just defining the
function within the class makes it inline implicitly. And you must include
the definition of functions just as the definition of the class, so
separation here brings little more pain than just doing the definitions
right at the place.
> if so, how is it done ?
The same way as the regular, just add 'inline' at front. :) Note, that for
member functions you do NOT say 'static', ever, at the implementation point
if it is outside the class def.
It's a question of style, but many people prefer separating the
declaration of a class from the implementation of its inline functions,
to keep the header tidy and clean. (After all, the class declaration
often doubles as a kind of "reference manual" to the usage of the class,
especially in the lack of better documentation, or if the documentation
is impractical to read.)
If you implement the inline function inside the class declaration,
then you can indeed skip the 'inline' keyword, ie:
//-------------------------------------------------------------
// Something.hh
//-------------------------------------------------------------
class Something
{
public:
// Implicitly inline, doesn't need the keyword:
int value() const { return something; }
};
//-------------------------------------------------------------
But if you want to separate the the declaration and the implementation
in the header, you have to specify the 'inline' keyword in the
implementation:
//-------------------------------------------------------------
// Something.hh
//-------------------------------------------------------------
class Something
{
public:
int value() const;
};
// 'inline' is required here:
inline int Something::value() const { return something; }
//-------------------------------------------------------------
As you said, it makes no difference whether the function is also
static or not. Just add the 'static' keyword in the declaration (the
implementation doesn't need it).
Yea, and for many cases the inline implementation documents what the
function does. :)
Where if it wouldn't there are good chances it is not fit for inlining
anyway.
Headers are good as dox, but you're better off to use doxygen or like
system -- so directly reading becomes only task of who changes it, the rest
can read the derived html, that well separates&jons the declarations, the
code, the attached text, no matter how it is spread in the source files.
I worked with those separated inlines -- at a time made some myself, my net
conclusion is it makes things worse.
Makes what worse?
readability, understandability, maitainance...
IMO the readability of a class declaration suffers if all the inline
functions are implemented inside the declaration. They tend to make the
class declaration very large (in lines of code).
If the class is very small (in number of inline member functions) and
all the inline functions are one-liners, then it's ok, but not otherwise.
Exactly :), that is how calsses shall better look. If there is a ton of
functions, and you want the compiler inline fat functions, I'd guess the
problems will not come from organizing them in the header, and will hardly
be cured by extracting those inlines.
And classes with non-obvoius interface need doxy-like tools even more.
> "Juha Nieminen" <nos...@thanks.invalid> az al锟絙biakat 锟絩ta a k锟絭etkezo
> h锟絩锟絲enetben: w3Hcm.219$sW4...@read4.inet.fi...
>> Balog Pal wrote:
>>> "Juha Nieminen" <nos...@thanks.invalid>
>>>> Balog Pal wrote:
>>>>> I worked with those separated inlines -- at a time made some
>>>>> myself, my net conclusion is it makes things worse.
>>>> Makes what worse?
>>>
>>> readability, understandability, maitainance...
>>
>> IMO the readability of a class declaration suffers if all the inline
>> functions are implemented inside the declaration. They tend to make
>> the class declaration very large (in lines of code).
>>
>> If the class is very small (in number of inline member functions)
>> and all the inline functions are one-liners, then it's ok, but not
>> otherwise.
>
> Exactly :), that is how calsses shall better look. If there is a ton
> of functions, and you want the compiler inline fat functions, I'd
> guess the problems will not come from organizing them in the header,
> and will hardly be cured by extracting those inlines.
When I have eight functions each a page long, I don't like them inside
the declaration. Rips the context apart.
Gerhard
When I have eight functions each a page long, I know I've done something
wrong!
--
Ian Collins
I'm not talking about one-liners vs. 100-liners.
Many functions which may be desirable to be inlined because of
efficiency are often 3-5 lines long, sometimes even a bit more. Add to
this the space taken by the curly braces, plus possibly all the function
parameters not fitting one single line, and you will have short
functions taking considerable amounts of visual space.
>Balog Pal wrote:
>> With member functions you rarely spell "inline", as just defining the
>> function within the class makes it inline implicitly. And you must include
>> the definition of functions just as the definition of the class, so
>> separation here brings little more pain than just doing the definitions
>> right at the place.
>
> It's a question of style, but many people prefer separating the
>declaration of a class from the implementation of its inline functions,
>to keep the header tidy and clean. (After all, the class declaration
>often doubles as a kind of "reference manual" to the usage of the class,
>especially in the lack of better documentation, or if the documentation
>is impractical to read.)
Me included - a habit formed in languages like Modula 2 and Ada, and
an objection I have to some other languages. Even if your editor can
do "folding", can you assume that everyone elses can? And what about
printed listings?
Then again, there's always Doxygen.
>I worked with those separated inlines -- at a time made some myself, my net
>conclusion is it makes things worse.
From call sites, you only see the name. If the code is a better quick
description than the name, you probably shouldn't be using a function
at all - you are reducing the readability of callers for no good
reason. Having the code there at the declaration site should ideally
be redundant - clutter and distraction, rather than informative - and
therefore that clutter should be moved somewhere else.
Of course one problem with replying in threads like this is that you
can end up giving a falsely polarised misrepresentation of your actual
views. On a different day, and reading different posts first, I might
easily have made the same point you did.
Also, Java and C# require all method definitions to be kept with the
declarations, IIRC, whereas Ada takes the opposite view with strict
separation of specifications and bodies. The fact that different
languages take different extremist viewpoints without the world ending
probably suggests that it's a bit of a non-issue.
>When I have eight functions each a page long, I don't like them inside
>the declaration. Rips the context apart.
Why on Earth are you inlining page-long functions? That's a pretty
fair size limit for non-inlined functions.
For me, the issue is more width than length - can I reasonably fit the
whole definition on a single line. As soon as the one-line rule
breaks, I already need five lines, including the blank ones, as...
void mymethod1 () { ... }
void mymethod2 () { ... }
becomes...
void mymethod1 ()
{
...
}
void mymethod2 ()
{
...
}
An occasional multi-liner isn't a disaster, but if it really needs
multiple lines, it probably shouldn't be inline anyway.
Not necessarily - moving complexity to the call-graph doesn't
eliminate it, and some functions really are just do-this then do-that
then do-the-other. A comment at the top of each chunk may make more
sense than splitting it up.
But page-long *inline* member functions...
To me, it suggests an ex-Java or C# programmer who hasn't absorbed a
certain key fact about C++.
One or two may be, but eight?
> To me, it suggests an ex-Java or C# programmer who hasn't absorbed a
> certain key fact about C++.
Or a PHP programmer.
--
Ian Collins
>Stephen Horne wrote:
>> On Sat, 01 Aug 2009 18:10:44 +1200, Ian Collins <ian-...@hotmail.com>
>> wrote:
>>
>>> Gerhard Fiedler wrote:
>>>> When I have eight functions each a page long, I don't like them inside
>>>> the declaration. Rips the context apart.
>>> When I have eight functions each a page long, I know I've done something
>>> wrong!
>>
>> Not necessarily - moving complexity to the call-graph doesn't
>> eliminate it, and some functions really are just do-this then do-that
>> then do-the-other. A comment at the top of each chunk may make more
>> sense than splitting it up.
>
>One or two may be, but eight?
I have a current example where the number is closer twenty. A DSL - a
source-to-source translater. Each method is basically just dumping out
a chunk of text with occasional substitutions etc using lots of stream
insertion.
Of course your reaction might well be that I should be using template
text files/resources with substitution markers, and getting most of
that out of the code completely. The reason I haven't done that yet is
that another DSL I'm writing is designed to handle template output
jobs such as this, and provide a bit more than a simple
substitute-these-markers transformation. Sadly, you can't use a DSL
until you've written the b*****d thing.
The worst thing is that I thought my existing regular grammar/state
machine compositing code would do the job - didn't think it through
properly. Now I have an issue which implies a significant change to
that model. What was supposed to be just-add-parser-and-text-output
has become a heada^H^H^H^H^H^H^H an interesting theory/design problem.
> Why not?
> > I dont ever recall seeing "static" and "inline" together.
> With member functions you rarely spell "inline", as just
> defining the function within the class makes it inline
> implicitly. And you must include the definition of functions
> just as the definition of the class, so separation here brings
> little more pain than just doing the definitions right at the
> place.
At least in the places I've worked, putting the definition
inside the class has been forbidden. (There are several reasons
for this, and they don't apply everywhere, but on the whole, I'd
go along with the rule, at least for definitions in exported
header files.)
> > if so, how is it done ?
> The same way as the regular, just add 'inline' at front. :)
> Note, that for member functions you do NOT say 'static', ever,
> at the implementation point if it is outside the class def.
Yes, and you don't say "inline", usually, if the implemention is
inside the class. But both are allowed on the same function, in
any order.
--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
> > Balog Pal wrote:
> >> With member functions you rarely spell "inline", as just
> >> defining the function within the class makes it inline
> >> implicitly. And you must include the definition of
> >> functions just as the definition of the class, so
> >> separation here brings little more pain than just doing the
> >> definitions right at the place.
> > It's a question of style, but many people prefer separating
> > the declaration of a class from the implementation of its
> > inline functions, to keep the header tidy and clean. (After
> > all, the class declaration often doubles as a kind of
> > "reference manual" to the usage of the class, especially in
> > the lack of better documentation, or if the documentation is
> > impractical to read.)
> Yea, and for many cases the inline implementation documents
> what the function does. :)
Perhaps with the help of a few macros:-). (I'm thinking of the
usual programming by contract technique. I've heard of people
who defined special macros, along the lines of "PRECONDITION()",
"POSTCONDTION()", and "INVARIANT()", and insisted that the
non-virtual public function be in the class definition, so that
the invocation of such macros be visible. For various reasons,
I've never used this technique, however.)
> Where if it wouldn't there are good chances it is not fit for
> inlining anyway.
> Headers are good as dox, but you're better off to use doxygen
> or like system -- so directly reading becomes only task of who
> changes it, the rest can read the derived html, that well
> separates&jons the declarations, the code, the attached text,
> no matter how it is spread in the source files.
You're even better off doing things in the correct order:
writing the documentation first (e.g. as cweb, or using a tool
like Rose), and generating the header files from it. And
depending on the tool, it might not easily support such code in
the header functions (Rose doesn't), at least if you want to
make your header files "derived objects", not edited later.
> I worked with those separated inlines -- at a time made some
> myself, my net conclusion is it makes things worse.
It probably depends on what you're doing. Putting code in the
class definition doesn't make reading the class definition
simpler, except for almost trivial classes (functional objects,
etc.). Or, of course, if that code really is part of the
"documentation".
Just to be iconoclastic: I'd say that depends on the size of a
page. A long, long time ago, a "page", meant a screenful on a
80x24 character terminal---a class with eight functions, none of
which are more than 24 lines long, sounds acceptable to me. (On
the other hand, I once worked with a person who used an
exceptionally small font on a Sparc---his "screenful" pages were
something like 200x100 characters. And he used them. The
results definitely weren't what I would consider acceptable.)
:)
> A long, long time ago, a "page", meant a screenful on a
> 80x24 character terminal---a class with eight functions, none of
> which are more than 24 lines long, sounds acceptable to me. (On
> the other hand, I once worked with a person who used an
> exceptionally small font on a Sparc---his "screenful" pages were
> something like 200x100 characters. And he used them. The
> results definitely weren't what I would consider acceptable.)
I use 30" panels and a 12 point font, so a page is about 112 lines.
--
Ian Collins
There may be many reasons why a function cannot be written completely
on one single line, other than the function consisting of a lot of code.
For example, your variable names may be descriptive and long, in which
case you easily hit your favorite maximum line length (personally I use
80 characters, I hear other people use eg. 100 characters) even if the
function is nothing more than a 'return' and some simple arithmetic
involving a couple of variables. (Heck, even if your function does
nothing more than return the value of a variable and nothing else, the
entire function definition and implementation may be too long because of
the names being used, plus indentation.)
Also it's not unusual for an inline function to, for example, do one
of two possible things (using a conditional), which is most naturally
written as at least two lines of code. Even if the code was so short
that you could fit it all into one single line, writing an entire
if/else statement into one line is more obfuscatory than anything else.
Sometimes it just feels tempting to implement a function which is
really, really short, right there in the declaration, as it saves
writing effort. A typical example goes like:
class MyClass
{
int value;
public:
MyClass(int someValue): value(someValue) {}
...
};
>Stephen Horne wrote:
>> An occasional multi-liner isn't a disaster, but if it really needs
>> multiple lines, it probably shouldn't be inline anyway.
>
> There may be many reasons why a function cannot be written completely
>on one single line, other than the function consisting of a lot of code.
As I said, "an occasional multi-liner isn't a disaster". Also note the
word "probably" - there is no absolute here even WRT inline.
However, note what I was replying to - would you really have page-long
inline functions?
> For example, your variable names may be descriptive and long, in which
>case you easily hit your favorite maximum line length (personally I use
>80 characters, I hear other people use eg. 100 characters) even if the
>function is nothing more than a 'return' and some simple arithmetic
>involving a couple of variables. (Heck, even if your function does
>nothing more than return the value of a variable and nothing else, the
>entire function definition and implementation may be too long because of
>the names being used, plus indentation.)
Absolutely. I said something about the polarising effect of replying
in threads elsewhere - I doubt our positions are really that different
in practice. For example, are you really claiming that page-long
functions should be inlined? Depending on font selection, I'd guess
you could get over 100 text lines on a single A4 side - the point I
was replying to wasn't about a few long names and a single if/else
conditional.
BTW - even the dumb terminals of 20 years ago could manage 132
characters across. I don't want to start another religious war here,
but allowing myself those extra 52 characters obviously allows me a
lot more opportunity to keep things on a single line. Subtract the
function name and parameters, and I've probably more than doubled the
amount of remaining space available for the body compared with your 80
character limit.
In that context, a single line function containing a simple if/else
conditional and referencing a long name or three is perfectly
reasonable.
>You're even better off doing things in the correct order:
>writing the documentation first (e.g. as cweb, or using a tool
>like Rose), and generating the header files from it.
I don't really agree. Sure, planning before coding is a good thing.
But "Rose" I assume refers to the UML tool, and UML is really just an
incomplete visual programming language - only a bit more complex and
confusing to work with than most plain text programming languages.
> I don't really agree. Sure, planning before coding is a good
> thing. But "Rose" I assume refers to the UML tool, and UML is
> really just an incomplete visual programming language - only a
> bit more complex and confusing to work with than most plain
> text programming languages.
UML is a lot more than that---unlike C++ (and most programming
languages) it's a descriptive language. Obviously, it doesn't
perform miracles, you still have to think, and to pay attention
to details, but it does attact the problem at a higher level of
abstraction than that of the C++ it generates.
And if you don't like UML, what do you like? You do need some
way of describing how the pieces fit together. Until you know
how the pieces fit together, i.e. the role and the
responsibility of each piece, you can't start writing them (or
writing the tests for them, if that's the order you prefer).
And until you've actually written something down, black on
white, you don't really know it.
> class MyClass
> {
> int value;
I didn't say it wasn't tempting. I didn't say anything, really,
about how easy it is to write. The reason it is usually
forbidden has to the with how easy it is to read. There's also
a very philosophical aspect: the header file is what the clients
see, and the implementation of the functions is logically
something they shouldn't see. (Of course, private members are
also something they shouldn't see. But the language is what it
is, and we have to live with it.)
>>I worked with those separated inlines -- at a time made some myself, my
>>net
>>conclusion is it makes things worse.
>
> From call sites, you only see the name. If the code is a better quick
> description than the name, you probably shouldn't be using a function
> at all - you are reducing the readability of callers for no good
> reason.
Number 1 enemy is redundancy. Keeping to DRY (don't repeat yourself) is
vital to create working and maitainable project.
> Having the code there at the declaration site should ideally
> be redundant - clutter and distraction, rather than informative - and
> therefore that clutter should be moved somewhere else.
As mentioned before, it is a clutter only to those ignoring the tools that
remove it. IDEs have 'outlining' for a decade at least as mainstram
feature. doxygen produces a way superior reading material at little cost.
Isn't it a problem created by the 'vi religion'? ;-)
Really, the source browser/navigator makes both code reading and writing way
more effective, and once you have it, the actual content of the source
becomes a mostly ignoreable issue.
> Of course one problem with replying in threads like this is that you
> can end up giving a falsely polarised misrepresentation of your actual
> views.
LOL. It's always just a projecion, and one selected for some purpose.
> On a different day, and reading different posts first, I might
> easily have made the same point you did.
Yea, happens often.
> Also, Java and C# require all method definitions to be kept with the
> declarations,
But they (supposedly) handle the dependencies ways better.
With C++ to include implementation at the declaration point will hardly
work, due to dependencies. (where I did not even mention overload sets,
macros and other stuff that can change the meaning of a code fragment just
moved arund...)
> IIRC, whereas Ada takes the opposite view with strict
> separation of specifications and bodies. The fact that different
> languages take different extremist viewpoints without the world ending
> probably suggests that it's a bit of a non-issue.
:)
I wouldn't like to read code where if/else conditionals are written in
one single line...
>> > It's a question of style, but many people prefer separating
>> > the declaration of a class from the implementation of its
>> > inline functions, to keep the header tidy and clean. (After
>> > all, the class declaration often doubles as a kind of
>> > "reference manual" to the usage of the class, especially in
>> > the lack of better documentation, or if the documentation is
>> > impractical to read.)
>> Yea, and for many cases the inline implementation documents
>> what the function does. :)
>Perhaps with the help of a few macros:-).
I was thinking of trivial cases, like getters, syntax sugar functions and
such.
Also there are 'rule' functions.
>(I'm thinking of the
>usual programming by contract technique. I've heard of people
>who defined special macros, along the lines of "PRECONDITION()",
>"POSTCONDTION()", and "INVARIANT()", and insisted that the
<non-virtual public function be in the class definition, so that
>the invocation of such macros be visible. For various reasons,
>I've never used this technique, however.)
I was giving it a thought many times, but didn't use in that form. Though
many times I start the function with ASSERT lines (same idea as PRECONDITION
above), it communicates the idea of params or state better than comments,
and 'works' too. Lately I made an extra macro ASSERT_DX,
docmentation-purposed assert, that is intended to remove the content in
release build. Mostly used where the condition is really already checked
earlier, but helps much in reading, and knowing what is left after
elimination.
> Where if it wouldn't there are good chances it is not fit for
> inlining anyway.
No, it goes with the regular functions.
>> Headers are good as dox, but you're better off to use doxygen
>> or like system -- so directly reading becomes only task of who
>> changes it, the rest can read the derived html, that well
>> separates&jons the declarations, the code, the attached text,
>> no matter how it is spread in the source files.
>You're even better off doing things in the correct order:
>writing the documentation first (e.g. as cweb, or using a tool
>like Rose), and generating the header files from it.
Guess that depends much on the project. I looked at Rose trials around 2000,
did not impress me a bit. And a recent try on AgroUML was way in the
negatives -- the tool does not help at all, but takes away time when I just
want to draw the design I have in mind. Reading back is even worse --
practicly no control over what to show and how. Modification even worse.
Seem we still have to wait long till 'mindmapping' soft meets the modeling
and codegen tools.
> And
>depending on the tool, it might not easily support such code in
>the header functions (Rose doesn't), at least if you want to
>make your header files "derived objects", not edited later.
Working with 'wizards' and code generators (mainly MFC-supporting stuff),
left me with opinion, that such code shall be completely write-only. (But
definitely not editable).
I made such a generator translating database to records, relations and all
the stuff -- producing a file for the compiler only, and completely
regenerated on any change.
Well, at that time I did not yet use version control merge tools -- that
could probably deal with an editable file too.
Currently I'd rather see the opposite direction, source browser augmented to
produce all kind of diagrams. (What is actually happening, but have the
same problems: no good change consolidation, if I rearrange the class chart,
adjust it to show/hide the relevant elements, those get washed away. Too
bad.)
>> I worked with those separated inlines -- at a time made some
>> myself, my net conclusion is it makes things worse.
>It probably depends on what you're doing.
LOL, it ABSOLUTELY depends on that... :)
>Putting code in the
>class definition doesn't make reading the class definition
>simpler, except for almost trivial classes (functional objects,
>etc.). Or, of course, if that code really is part of the
>"documentation".
In a large project I did recently my policy was that any code appearing
within the class def is just as 'published' as the interface: considered
stable and anyone can build on it as on any other form of dox. (That limits
the options pretty much ;)
Correction: that applies only to normal classes, not to template lib. For
templates I prefer writing stuff right in the class as much as possible,
move out only what is necessary to compile. The policy there is simpler, I
don't expect people to read that header, only the dox.
And if there's a need to read the template the trouble is likely bigger so
source layout is not a factor.
--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orient�e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France, +33 (0)1 30 23 00 34
>On Aug 2, 10:36 pm, Stephen Horne <sh006d3...@blueyonder.co.uk> wrote:
>> On Sun, 2 Aug 2009 03:20:04 -0700 (PDT), James Kanze
>>
>> <james.ka...@gmail.com> wrote:
>> >You're even better off doing things in the correct order:
>> >writing the documentation first (e.g. as cweb, or using a tool
>> >like Rose), and generating the header files from it.
>
>> I don't really agree. Sure, planning before coding is a good
>> thing. But "Rose" I assume refers to the UML tool, and UML is
>> really just an incomplete visual programming language - only a
>> bit more complex and confusing to work with than most plain
>> text programming languages.
>
>UML is a lot more than that---unlike C++ (and most programming
>languages) it's a descriptive language.
"class myderived : public mybase" is precisely as descriptive as
drawing one of a range of arrow shapes on a line between two boxes.
Both give exactly the same information - the one class inherits from
the other. Both can only be understood if you have learned the syntax
of the appropriate language. If that sounds wrong, ask yourself how
many different kinds of relationships might be represented by an arrow
between two boxes.
UML has some niceties like making "abstract" explicit - but then,
IIRC, so do some other programming languages. Certainly there's no
reason why such annotations couldn't be added to a programming
language. Just as there's no reason why you can't add a comment to say
the same thing in C++ source code. A Doxygen comment would be the
perfect place IMO.
A relevant paper...
http://martinfowler.com/articles/newMethodology.html
Particularly the "Separation of Design and Construction" section, in
which Fowler points out that...
"The problem with a UML-like design is that it can look very good on
paper, yet be seriously flawed when you actually have to program the
thing."
This from the author of the "UML Distilled" books, and it fits my
experience WRT all heavyweight design methods. State diagrams, data
flow diagrams, entity-relationship diagrams, class diagrams and all
the rest are useful and all have their place, but as soon as you adopt
a specific methodology and a standardized syntax, you'll end up
pedanting on that instead of the actual design.
Basically, you end up putting all your effort into implementing the
methodology and putting all the dots and commas in the right places in
the methodology deliverables, which is not the same thing as designing
your product. And you end up with something that simply isn't a good
design given the constraints of the final implementation language.
I pedanted on a design representation using Mascot once, only to find
out later that Mascot really didn't match perfectly to Ada, and that
beautiful design simply couldn't be implemented. I was also once in a
similar situation WRT an IIRC Ward/Mellor dataflow based design, but
in this case I wasn't responsible for the design - it had been signed
off by the big bosses before I was taken on, and this was my first
real programming job. Fortunately, people were willing to see reason
when I pointed out that that design couldn't be implemented, but it
wasn't exactly an easy situation. You see, this was a defense company
and there were contracts based on that design document.
Also...
"These kinds of questions led Jack Reeves to suggest that in fact the
source code is a design document and that the construction phase is
actually the use of the compiler and linker. Indeed anything that you
can treat as construction can and should be automated."
And this again fits my experience. Everywhere I've worked, the primary
source of design documentation was always the source code, for me and
AFAICT every other programmer. Any other form of documentation is
always outdated and misleading. Even comments can get outdated and
misleading.
The best design documentation I've ever had access to is a subversion
repository. Either that, or the back-of-whatever-scrap-paper-was-handy
doodle that somehow is still the primary reference a year later.
>And if you don't like UML, what do you like? You do need some
>way of describing how the pieces fit together.
Yes you do, and diagrams can do that. The diagrams that Doxygen give
me are UML diagrams, but I'm not the one pedanting on the syntax
details - Doxygen is. Though it says something that the situation is
just like it was for me 20+ years ago, when anyone wanting a decent
grade rewrote the design documents from the source code before handing
in their work. These days, the only difference is that a software tool
does the rewriting for me.
And before you say it, yes, I agree that in itself Doxygen cannot
write design documentation - everything depends on the comments. But
then I've always written a lot of the comments before I write the
code. It just means that now I write most of them as Doxygen
annotations. Of course, as always, more than a few comments get
deleted later because the code says it better.
I also often have diagrams before the coding starts, of course, using
simple, often ad-hoc conventions, making sure that the meaning is
clear without a three week training course.
When it comes to deciding the details, I decide them in C++ so that
they'll work in C++.
Your false assumption here is that it is impossible to understand the
structure of a design without adopting some heavyweight methodology
like UML. I would argue that you have things backwards - when it comes
to understanding a design, heavyweight methodologies and overcomplex
visual representations that require whole books to list all the
various distractions - sorry, details - are the problem, not the
solution.
>"Stephen Horne" <sh006...@blueyonder.co.uk>
>
>>>I worked with those separated inlines -- at a time made some myself, my
>>>net
>>>conclusion is it makes things worse.
>>
>> From call sites, you only see the name. If the code is a better quick
>> description than the name, you probably shouldn't be using a function
>> at all - you are reducing the readability of callers for no good
>> reason.
>
>Number 1 enemy is redundancy. Keeping to DRY (don't repeat yourself) is
>vital to create working and maitainable project.
Good basic principle, but we are talking about a corner case here -
trivial bits of code.
Would you really insist that someone write an increment function
rather than repeat the increment operator? And what would you then do
about the repeated calls to that increment function?
The cases I'm talking about really aren't far removed from that.
>> Having the code there at the declaration site should ideally
>> be redundant - clutter and distraction, rather than informative - and
>> therefore that clutter should be moved somewhere else.
>
>As mentioned before, it is a clutter only to those ignoring the tools that
>remove it. IDEs have 'outlining' for a decade at least as mainstram
>feature.
I've been looking for a way to fold away the bodies of functions on my
printouts. I still can't see how it's done ;-)
Actually, I lie - I hardly ever print listings these days. I still
miss the sound of all those little pins hitting the paper :-(
> doxygen produces a way superior reading material at little cost.
I agree - but you still have to re-run it to get up-to-date docs.
>Isn't it a problem created by the 'vi religion'? ;-)
I don't use "virtually impossible". It was forced on me once, but I'm
quite seriously allergic, so I argued that forcing me was a breach of
my human rights. I'm also allergic to emacs. My edlin allergy is much
less of an issue these days.
I like folding editors, and always have, just as I liked PC Outline
back in the days of "ideas processors". I even used the GFA Basic
folding editor on the Atari ST back when I was about 18.
It's just that they never really seem to become a habit. Other than,
oddly enough, with GFA Basic. Classview for navigation, yes. Folding,
yes, very nice, I always want it available - but by the time I think
of using it, it's already a distraction.
Being trivial has nothing to do with DRY. Redundancy that takes only 10
letters of text or 2 objects or a single operation is redundancy all the
same, and has the same ill effects.
Say, VAT calculation is such a trivial thing, it is base_price*0.25. Bet it
is a common (and serious) mistake to avoid writing a function and use that
consistently, instead of inlining the expression in the code.
> Would you really insist that someone write an increment function
> rather than repeat the increment operator?
"increment" is an operation, with well defined semantics. It does not
matter a bit whether you invoke it through a function or an operator, or
magic. The important thing is where you use it, you mean to do an
increment. And not something else. With special attention to application of
some expression that just *happens* to match increment at the moment.
> And what would you then do
> about the repeated calls to that increment function?
Just because you have a zillion instances of something does not imply they
are connected in any way. (Especially in the "way" we look for -- that a
change to one should drag the change of others.)
>>As mentioned before, it is a clutter only to those ignoring the tools that
>>remove it. IDEs have 'outlining' for a decade at least as mainstram
>>feature.
>
> I've been looking for a way to fold away the bodies of functions on my
> printouts. I still can't see how it's done ;-)
You waste trees on printouts? Shame on you. :-| Especially printouts of
the source code? What for?
> Actually, I lie - I hardly ever print listings these days.
Okay then :) My 'these days' in this regards is over a decade. Sometimes
a print of a chart, graph, table can come handy, but that is just a page or
two -- to stick for reference, or to draw on it by hand.
>> doxygen produces a way superior reading material at little cost.
>
> I agree - but you still have to re-run it to get up-to-date docs.
Hardly a problem since make tools discovered... We have way more problems
with a) dox that are missing entirely and b) ignorant people who don't read
dox (including the handy ones at fingertips, online pages, man, etc...)
IMO outdated dox is more like a gremlin. :)
>>Isn't it a problem created by the 'vi religion'? ;-)
>
> I don't use "virtually impossible". It was forced on me once, but I'm
> quite seriously allergic, so I argued that forcing me was a breach of
> my human rights.
LOL. Will mark that one :)
> I'm also allergic to emacs. My edlin allergy is much
> less of an issue these days.
>
> I like folding editors, and always have, just as I liked PC Outline
> back in the days of "ideas processors". I even used the GFA Basic
> folding editor on the Atari ST back when I was about 18.
>
> It's just that they never really seem to become a habit.
I too use that feature infrequently -- what is IMO an indication that the
text around is rarely an issue in usual cases. I do use syntax hilite to
to maximum effect. (Recall I made such feature back around '85 on my C64,
it was really cool and helping.) The fact that code and comments are
visually distinct makes it easy for the eye to read one or the other. And
screens are big enough to read ad boredom before dragging in the next item.
> Other than,
> oddly enough, with GFA Basic. Classview for navigation, yes. Folding,
> yes, very nice, I always want it available - but by the time I think
> of using it, it's already a distraction.
I mostly restrict to 'collapse all' (then whatever is hit by search
expands...) Really there is a miss of control, I can't lock something as
hidden or restrict search/navigation to shown content (at least I'm not
aware of that).
>
>"Stephen Horne" <sh006...@blueyonder.co.uk>
>>>Number 1 enemy is redundancy. Keeping to DRY (don't repeat yourself) is
>>>vital to create working and maitainable project.
>>
>> Good basic principle, but we are talking about a corner case here -
>> trivial bits of code.
>
>Being trivial has nothing to do with DRY. Redundancy that takes only 10
>letters of text or 2 objects or a single operation is redundancy all the
>same, and has the same ill effects.
Really - so you would never call std::stable_sort twice in the same
program, I presume, because simply identifying the method requires 16
letters, a full 60% over your limit.
Sorry, but you did ask for it ;-)
>Say, VAT calculation is such a trivial thing, it is base_price*0.25. Bet it
>is a common (and serious) mistake to avoid writing a function and use that
>consistently, instead of inlining the expression in the code.
Restoring lost context, what I originally said, word-for-word is...
: If the code is a better quick
: description than the name, you probably shouldn't be using a function
: at all - you are reducing the readability of callers for no good
: reason.
In your example, your VAT code isn't a better quick description than
the named function that replaces, though I'd suggest that naming the
constant 0.25 as vat_rate MAY be enough, and you should be doing that
even if you keep the function anyway.
The main reason the named constant might not be enough is because we
are only discussing one issue here, and another obvious issue has come
into play - that calculation is likely to be used in a lot of
different places, and any modifications may need to be applied
consistently in all those cases. For example, you might need to worry
about rounding rules. Obviously it's better to have a single site to
apply that change.
That said, shame on you for using floating point for money
calculations - how would you feel if your bank told you that your
balance was "oh, our guess is maybe around such-and-such,
more-or-less".
>And not something else. With special attention to application of
>some expression that just *happens* to match increment at the moment.
Absolutely - couldn't agree more.
>> And what would you then do
>> about the repeated calls to that increment function?
>
>Just because you have a zillion instances of something does not imply they
>are connected in any way.
Absolutely. Lots of people write functions for "operations" that are
really just a couple of operators that happen to occur together a lot,
or fatten interfaces with functions that are just variations on one
core call, but with one or two parameters filled in or with an extra
operator applied or something. The name often adds nothing that you
couldn't see in the code right from the start, and even hides a detail
that may well have been important for readability. THAT is what I'm
against.
I even think there's one or two offenders in <algorithms> - functions
where the name might serve some value, maybe, but the code is clear
and concise without it, or where the name is even misleading.
Furthermore, conditions can be obscured - not so much by the algorithm
functions themselves, but by the need for predicates, requiring those
(often trivial) conditions to be moved into separate functions whether
it makes good sense or not. Either that or use one of those kludgy
pseudo-lambda things.
std::remove is actually worth mentioning, not just because the name is
misleading, but because it's hard to think of a clear, concise
non-misleading alternative name for what it does - and while this
might be forgivable in a standard library that any competent C++
programmer should be familiar with, similar issues with finding an
appropriate name aren't that unusual.
As I said, it's often clearer to just write the code. It may not be
that much more code before you abstract out - maybe you'll have an
erase_all_xxxx function rather than call std::remove_if with a
predicate and then std::erase, but writing that loop in full is no big
deal.
If the code is self describing, leave it alone. If the code requires a
comment, then consider putting it in an appropriately named function.
--
Ian Collins
> "Stephen Horne" <sh006...@blueyonder.co.uk>
>>>Number 1 enemy is redundancy. Keeping to DRY (don't repeat yourself) is
>>>vital to create working and maitainable project.
>>
>> Good basic principle, but we are talking about a corner case here -
>> trivial bits of code.
>
> Being trivial has nothing to do with DRY. Redundancy that takes only 10
> letters of text or 2 objects or a single operation is redundancy all the
> same, and has the same ill effects.
>
> Say, VAT calculation is such a trivial thing, it is base_price*0.25. Bet it
> is a common (and serious) mistake to avoid writing a function and use that
> consistently, instead of inlining the expression in the code.
Yes, trivial, but already you've got a bug here.
Here it's: round(base_price*0.196,2)
But for another shop or another product it'd be also wrong to write:
round(base_price*VAT_RATE,CURRENCY_DECIMALS)
since the VAT rate would depend on the residence of the buyer and/or the product.
round(base_price->amount() * vat_rate(seller,buyer,product),base_price->currency()->decimals())
And vat_rate is not the kind of function you would want to inline I can assure you.
--
__Pascal Bourguignon__
> >>I worked with those separated inlines -- at a time made some
> >>myself, my net conclusion is it makes things worse.
> > From call sites, you only see the name. If the code is a
> > better quick description than the name, you probably
> > shouldn't be using a function at all - you are reducing the
> > readability of callers for no good reason.
> Number 1 enemy is redundancy.
With regards to information, redundancy is good. Duplicate
information is bad. (Information is redundant when it is used
to validate or verify. It's duplicate when you sometimes use
one source, sometimes another, under the premise that they are
the same.)
> Keeping to DRY (don't repeat yourself) is vital to create
> working and maitainable project.
Some redundancy is necessary for error checking.
--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
[...]
> You waste trees on printouts? Shame on you. :-| Especially
> printouts of the source code? What for?
To study it in the train, on the way home.
> >>Isn't it a problem created by the 'vi religion'? ;-)
Just for the record: modern versions of vi (i.e. vim) do support
folding.
[...]
> If the code is self describing, leave it alone. If the code
> requires a comment, then consider putting it in an
> appropriately named function.
I like that one.
Isn't that what the laptop was invented for?
--
Ian Collins
[...]
> Yes, trivial, but already you've got a bug here.
> Here it's: round(base_price*0.196,2)
(By "here", I presume you mean France, given the value.) That's
not totally right. First it's only right if the multiplication
of base_price * 0.196 is exact, which can only be the case (for
starters) if 0.196 can be exactly represented (which isn't the
case on the machines I know---you have to use decimal).
Secondly, of course, it depends (as you point out in the part
I've cut).
[...]
> And vat_rate is not the kind of function you would want to
> inline I can assure you.
That's for sure.
But maybe it was just meant to be a simple example, as the first
thing which came to mind, and not to be taken too literally.
> >> <james.ka...@gmail.com> wrote:
> >> >You're even better off doing things in the correct order:
> >> >writing the documentation first (e.g. as cweb, or using a tool
> >> >like Rose), and generating the header files from it.
> >> I don't really agree. Sure, planning before coding is a good
> >> thing. But "Rose" I assume refers to the UML tool, and UML is
> >> really just an incomplete visual programming language - only a
> >> bit more complex and confusing to work with than most plain
> >> text programming languages.
> >UML is a lot more than that---unlike C++ (and most programming
> >languages) it's a descriptive language.
> "class myderived : public mybase" is precisely as descriptive
> as drawing one of a range of arrow shapes on a line between
> two boxes. Both give exactly the same information - the one
> class inherits from the other. Both can only be understood if
> you have learned the syntax of the appropriate language. If
> that sounds wrong, ask yourself how many different kinds of
> relationships might be represented by an arrow between two
> boxes.
UML is a lot more than just inheritance (although when multiple
inheritance and virtual inheritance is involved, it is still a
lot clearer than the sources, where all you see is the immediate
inheritance of each class). It's defining how the various
components interact together. More generally, it's a higher
level of abstraction.
> UML has some niceties like making "abstract" explicit - but
> then, IIRC, so do some other programming languages. Certainly
> there's no reason why such annotations couldn't be added to a
> programming language. Just as there's no reason why you can't
> add a comment to say the same thing in C++ source code. A
> Doxygen comment would be the perfect place IMO.
> A relevant paper...
> http://martinfowler.com/articles/newMethodology.html
> Particularly the "Separation of Design and Construction"
> section, in which Fowler points out that...
The problem is that Fowler doesn't really know much about what
he is calling the "engineering methodologies". His discription
of them, at any rate, doesn't correspond to anything I've seen
in well run organisations. (Although I don't doubt that any
methodology can be misused, or misinterpreted.)
> "The problem with a UML-like design is that it can look very
> good on paper, yet be seriously flawed when you actually have
> to program the thing."
That's why you have design reviews. The same thing holds true
at all levels---a piece of C++ code can look very good on paper,
but can cause the program to core dump when actually run.
In the end, the basic principle dates from at least Dijkstra.
You start at a high level, without worrying about the details,
and work down. At each level, you are concerned with that
level.
> This from the author of the "UML Distilled" books, and it fits
> my experience WRT all heavyweight design methods.
UML is NOT a heavyweight design method. It's as heavy or as
light as you want. Or as is needed.
> State diagrams, data flow diagrams, entity-relationship
> diagrams, class diagrams and all the rest are useful and all
> have their place, but as soon as you adopt a specific
> methodology and a standardized syntax, you'll end up pedanting
> on that instead of the actual design.
Why? Do you end up pedanting on C++, rather than the actual
program? Same principles apply. (Obviously, some people do,
and end up with overly complicated systems. But that's a
problem with the people, and the process, which allowed them to
do so, and not with the notation.)
> Basically, you end up putting all your effort into
> implementing the methodology and putting all the dots and
> commas in the right places in the methodology deliverables,
> which is not the same thing as designing your product. And you
> end up with something that simply isn't a good design given
> the constraints of the final implementation language.
One advantage of UML (as opposed to C++) is that you don't have
to worry about all of the dots and commas. It's a very open
language, since (at least large parts of it) are really only
read by people, and don't serve to generate machine code
directly. (And I'm tempted to say that if at the higher level,
the design doesn't fit the language, and the design was well
done, you should change the language. But C++ is pretty
flexible, and I've yet to find a design which it didn't fit.)
[...]
> "These kinds of questions led Jack Reeves to suggest that in
> fact the source code is a design document and that the
> construction phase is actually the use of the compiler and
> linker. Indeed anything that you can treat as construction can
> and should be automated."
> And this again fits my experience. Everywhere I've worked, the
> primary source of design documentation was always the source
> code, for me and AFAICT every other programmer. Any other form
> of documentation is always outdated and misleading. Even
> comments can get outdated and misleading.
Then you've never worked in a well run shop. The code is
reviewed against the documentation, and when changes are
necessary, the documentation is updated before changing the
code. In one case, the header files were generated completely
from Rose, and were treated as a derived object, which couldn't
be edited. More often, however, there was almost nothing in the
header that was edited, and in the same way you currently edit
the header and the source file, you'd edit the UML diagram and
the source file. With the difference that the UML diagram was a
lot more readable, and a lot easier to edit correctly than a C++
header file.
> The best design documentation I've ever had access to is a
> subversion repository. Either that, or the
> back-of-whatever-scrap-paper-was-handy doodle that somehow is
> still the primary reference a year later.
The problem with not having such tools (e.g. Rose) is that you
use some sort of graphic abstraction anyway. With Rose, it's
UML, and it's in the machine, where others can access it, review
it, and refer to it later. Without some such tool, it's scratch
paper on your desk, and it gets thrown out before you're
finished coding. (At least, that's been my case. I have heard
of people using a white board and a Poloroid camera---this was
before digital cameras.)
> >And if you don't like UML, what do you like? You do need
> >some way of describing how the pieces fit together.
> Yes you do, and diagrams can do that. The diagrams that
> Doxygen give me are UML diagrams,
But they're not complete (there are relationships that they
don't show, and there are no scenarios---in my experience, one
of the most important diagram types).
> but I'm not the one pedanting on the syntax details - Doxygen
> is.
There are more semantic details in the C++ code than in UML
diagrams. (Note that tools like Rose need to maintain
additional information, entered in various dialog boxes, in
order to "generate" the C++.)
> Though it says something that the situation is just like it
> was for me 20+ years ago, when anyone wanting a decent grade
> rewrote the design documents from the source code before
> handing in their work. These days, the only difference is that
> a software tool does the rewriting for me.
And in the companies I've worked in which used Rose, it was Rose
which did the rewriting in C++.
> And before you say it, yes, I agree that in itself Doxygen
> cannot write design documentation - everything depends on the
> comments. But then I've always written a lot of the comments
> before I write the code. It just means that now I write most
> of them as Doxygen annotations.
In my case, I write my comments as plain text (or simplified
HTML); I have a program which formats them into Doxygen
annotations (and since I use vim, it's no problem to switch to
text mode for the comments, then run the results through my
program). And the comments are written first, before I'll write
the code. But such comments can't cover everything. The header
file is the ideal place for detailed comments concerning a
single class or function, but where to you put more general
comments, concerning the relationship between several classes.
Or the scenarios; the time line of what happens (or would have
happened, if the code worked) for a given transaction.
A lot depends on what level you're working at. In my library
code, I don't really miss Rose that much---it's mostly a case of
one class doing a simple, specific job, and the essential things
to know are the pre- and post-conditions for each function, and
any class invariants. Even in some of the more complicated
cases, which a number of classes, the relationships are simple
enough to explain in plain words (a parse tree, with different
nodes having different derived types, for example). In my
business software, on the other hand, it's not unusual for a
single transaction to involve twenty or thirty different
objects; a clean graphic representation of the relationships
among these objects, and a couple of clear scenarios for typical
cases, make understanding much, much easier.
> Of course, as always, more than a few comments get deleted
> later because the code says it better.
It depends on what code. How does the code say that the vector
passed to a particular function must be sorted? (On the other
hand, I did once work in a place which required that every
function be documented with Doxygen-like comments, with a number
of required fields, like behavior, and one for each parameter.
So you ended up with something like:
// setAdministrativeState:
//
// \behavior
// Sets the administrative state to the
// new value
//
// \parameter newAdministrativeState
// The new value.
//
// \post
// getAdministrativeState() ==
// newAdministrativeState
//
// \throws
// Nothing.
// ---------------------------------------------------------
void setAdministrativeState(
AdministrativeState newAdministrativeState ) ;
I've yet to have met a programmer where the function signature
wouldn't have been enough:-). Even the post-condition is
implicit, given the name and the naming conventions in effect.
About the only time any comments would have been justified here
is if setting the administrative state had some other side
effects not implied by the pre- and post-conditions of other
functions. (Note that this was before the days of syntax
hilighting, or even color screens, so the // ---... line was
necessary to clearly separate the comment from the code. I'll
admit that I've gotten so used to it, that I still use it, even
though the comments in my editor display in a different color
than the code.)
There is no one right answer, but in this particular project,
Rose would have been a lot more helpful than all of the
Doxygen-like comments.
> I also often have diagrams before the coding starts, of
> course, using simple, often ad-hoc conventions, making sure
> that the meaning is clear without a three week training
> course.
Guess what? I've never had a course in UML (or Booch, which is
what I started with). I only recently read my first book about
it. That never stopped me from using it, and Rose. (It took me
less than ten minutes to learn enough Rose to use it for what I
was doing. It took me maybe ten years to acquire a similar
level of fluency in C++.)
> When it comes to deciding the details, I decide them in C++ so
> that they'll work in C++.
> Your false assumption here is that it is impossible to
> understand the structure of a design without adopting some
> heavyweight methodology like UML.
Your false assumption is that UML is a heavyweight methodology.
It's not; it's a lot easier to work in and understand than C++,
because it's a lot more forgiving (except for the parts that are
actually used to generate the C++), and it's at a much higher
level of abstraction.
> I would argue that you have things backwards - when it comes
> to understanding a design, heavyweight methodologies and
> overcomplex visual representations that require whole books to
> list all the various distractions - sorry, details - are the
> problem, not the solution.
Maybe. I've never encountered any such methodologies, however.
Con't see how that fits in the discussion.
>>Say, VAT calculation is such a trivial thing, it is base_price*0.25. Bet
>>it
>>is a common (and serious) mistake to avoid writing a function and use that
>>consistently, instead of inlining the expression in the code.
>
> Restoring lost context, what I originally said, word-for-word is...
>
> : If the code is a better quick
> : description than the name, you probably shouldn't be using a function
> : at all - you are reducing the readability of callers for no good
> : reason.
>
> In your example, your VAT code isn't a better quick description than
> the named function that replaces, though I'd suggest that naming the
> constant 0.25 as vat_rate MAY be enough, and you should be doing that
> even if you keep the function anyway.
No. Here using function CalculateVAT would be clearly preferred by all
means. It is not so good example to your text because that is a
clearstanding abstraction, and you can introduce a good name for it. But
in life there are business rule functions that are pretty weird, ad-hoc, and
you can't easily give them a name that makes sense to anyone outside. The
implementation (at a given moment) may be as trivial as the *.25 VAT
example. (I hoped someone notices that VAT actually depends on the product,
the time point, the country you sell it, so a real implementation is pretty
far from one shown, but as it happens, I saw many organisations that used
the simple form, because they (believed) to sell only certain products,,
only locally, and the rate was fix for some time...) It was also
interesting to correct those programs, or work around the limitations, when
the environment naturally changed. Or turned out the assumptions the
programmer made never really held.
> The main reason the named constant might not be enough is because we
> are only discussing one issue here, and another obvious issue has come
> into play - that calculation is likely to be used in a lot of
> different places, and any modifications may need to be applied
> consistently in all those cases. For example, you might need to worry
> about rounding rules.
Yeah. Rounding is a good example to extend the thing, and it is really part
of the algo.
> Obviously it's better to have a single site to apply that change.
:)
> That said, shame on you for using floating point for money
> calculations - how would you feel if your bank told you that your
> balance was "oh, our guess is maybe around such-and-such,
> more-or-less".
Near miss -- I didn't give away the type of the value holder. ;-)
>>Just because you have a zillion instances of something does not imply they
>>are connected in any way.
>
> Absolutely. Lots of people write functions for "operations" that are
> really just a couple of operators that happen to occur together a lot,
> or fatten interfaces with functions that are just variations on one
> core call, but with one or two parameters filled in or with an extra
> operator applied or something. The name often adds nothing that you
> couldn't see in the code right from the start, and even hides a detail
> that may well have been important for readability. THAT is what I'm
> against.
The other role of function is certainly to create an usable abstraction;
imposing a true abstraction barrier. With that ad-hoc approach it hardly
happens. And I agree, when the redindancy issue is not on the table, AND
the the reader shall know the implementation for whatever reason, then
inlining the code is better, and having it in separate is just distraction.
[note, that we are probably with a minority opinion here, I heard a plenty
of guidelines to reduce code chunks, fight complexometry scores, etc, this
introduce those very pseudo-functions. ]
> I even think there's one or two offenders in <algorithms> - functions
> where the name might serve some value, maybe, but the code is clear
> and concise without it, or where the name is even misleading.
mentioning algorithms, we hit right in the C++ imperfection that makes the
plain old for-loop still more readable than using for_each or some other
algos -- for the very reason the payload can not be introduced right there,
or even at a near and convenient place. In the next release lambdas will
solve that, hopefully well.
> Furthermore, conditions can be obscured - not so much by the algorithm
> functions themselves, but by the need for predicates, requiring those
> (often trivial) conditions to be moved into separate functions whether
> it makes good sense or not. Either that or use one of those kludgy
> pseudo-lambda things.
yea.
> std::remove is actually worth mentioning, not just because the name is
> misleading, but because it's hard to think of a clear, concise
> non-misleading alternative name for what it does - and while this
> might be forgivable in a standard library that any competent C++
> programmer should be familiar with, similar issues with finding an
> appropriate name aren't that unusual.
stl is broken in many ways -- too bad there was no other candidate to go
into standard. I.e. the idea of algos working on iter-ranges looks good on
paper, but IRL most time you process a full collection. And there is no
immediate support for that.
The remove gets broken due to that malfunction -- having just a range, it
can't play the erase game.
> As I said, it's often clearer to just write the code.
But going back to theory of things, we better separate the cases. IMO using
an algo where that is what you want would be ways superior, and serve the
purpose of good abstraction.
for_each reads ways better than however idiomatic for. Same for many
others. Being dragged down by other factors. :(
> It may not be
> that much more code before you abstract out - maybe you'll have an
> erase_all_xxxx function rather than call std::remove_if with a
> predicate and then std::erase, but writing that loop in full is no big
> deal.
Just imagine the mentioned problems magically fixed -- writing for() would
still not be a big deal, but immediately becoming ways inferior, in my eyes
at least.
>That's for sure.
>But maybe it was just meant to be a simple example, as the first
thing which came to mind, and not to be taken too literally.
It was chosen carefully to dig up this very conversation -- and match it
against a practice I actually encountered many times: just sprinkling the
multiplication and the number in the code...
It can be very elusive what looks trivial and what actually is...
>On Aug 3, 4:52 pm, Stephen Horne <sh006d3...@blueyonder.co.uk> wrote:
>> State diagrams, data flow diagrams, entity-relationship
>> diagrams, class diagrams and all the rest are useful and all
>> have their place, but as soon as you adopt a specific
>> methodology and a standardized syntax, you'll end up pedanting
>> on that instead of the actual design.
>
>Why? Do you end up pedanting on C++, rather than the actual
>program?
Yes, as does any C++ programmer who wants their program to actually
compile, let alone work.
Perhaps "pedant" isn't the right word, but the rules and idioms of the
language you are using clearly have to be followed, and they never
precisely match the design concept in your head.
The point applies in any language but, sadly, quite strongly in C++. I
have whined enough about certain features of C++ in this group, but
let's just say that even Stroustrup acknowledges that C++ and its
library were designed according to principles that place backward
compatibility and generality above simplicity, clarity and safety, and
this means that developing in C++ needs a quite a bit of care.
If UML dealt with things like the inherited C nasties and standard
library strangeness, it might well be the kind of tool that I'd grab
with both hands and never let go. But it doesn't.
I don't object to having illustrations - I only object to pedanting
over standard-defined notation issues instead of getting on with the
real work. I object when the process becomes an end in itself, rather
than the means to an end - a distraction from the real issue.
>> The best design documentation I've ever had access to is a
>> subversion repository. Either that, or the
>> back-of-whatever-scrap-paper-was-handy doodle that somehow is
>> still the primary reference a year later.
>
>The problem with not having such tools (e.g. Rose) is that you
>use some sort of graphic abstraction anyway. With Rose, it's
>UML, and it's in the machine, where others can access it, review
>it, and refer to it later.
Who says that doodle isn't in the machine? Who says you don't use
software?
My "all my own stuff" subversion repository literally contains pretty
much that. Text files, HTML notes, diagrams, word processor files,
etc. IMO, any repository should be the same - containing everything
relevant to the development of the project, not just the source code.
Being able to see the code at some past point is great - but seeing
the wider thought processes of the time is far better.
As you say, some silly scrap of paper gets lost, used to wipe up a
coffee spill, or whatever. But a scan, or a copy using some simple
diagram or vector drawing tool, is still, in essence, the same
diagram. Even when it's edited to reflect a design change, it's still
fundamentally different to something that's been forced to fit the
conventions of some standard.
The point is that that ad-hoc diagram is the important one - capturing
the essential feature of a design as produced at the time of the basic
idea, using whatever notation expressed the idea well, before people
have started adding endless details and imposing particular notational
and methodological standards and religious ideals.
>> And before you say it, yes, I agree that in itself Doxygen
>> cannot write design documentation - everything depends on the
>> comments. But then I've always written a lot of the comments
>> before I write the code. It just means that now I write most
>> of them as Doxygen annotations.
>
>In my case, I write my comments as plain text (or simplified
>HTML); I have a program which formats them into Doxygen
>annotations (and since I use vim, it's no problem to switch to
>text mode for the comments, then run the results through my
>program). And the comments are written first, before I'll write
>the code. But such comments can't cover everything. The header
>file is the ideal place for detailed comments concerning a
>single class or function, but where to you put more general
>comments, concerning the relationship between several classes.
I argue that the source code (and rewritings of it such as Doxygen
output) are *a* design document, not *the* design document.
If you really want Doxygen to be comprehensive in itself, there's
separate text files that are picked up by Doxygen along with the
source code, and there's the annotation "\page"...
"""
\page <name> (title)
Indicates that a comment block contains a piece of documentation that
is not directly related to one specific class, file or member. The
HTML generator creates a page containing the documentation.
"""
Personally, though, I think that has practical limits - so just put it
in another document. But *please* keep that document in your
repository, so readers can track the changes in that too.
> // \behavior
> // Sets the administrative state to the
> // new value
I pity you - but this is just the old overcommenting thing. Another
example of the process becoming an end in itself and defeating its own
purpose.
Even worse, perhaps, is "obsessive OOP" where everything has more
layers of abstraction than the thoughts of an art student on LSD, and
is hidden behind more barriers than there are between the typical
customer services number and someone who can actually help with your
issue.
Anything can be overdone.
True Doxygen expertise, IMO, is in not being an expert. It isn't when
you know all the annotations. It's when you don't know most of them
because you hardly ever need them. Most of my methods, for example,
have a "\brief" description, often (but not always) followed by a
detailed description. "\param" I use in rare cases, and I don't recall
ever using "\return".
Mind you, I think I see your point. Everything can be overdone. That
doesn't mean that doing it right is wrong.
If Rose is, in effect, a visual DSL then I have no objection. Since I
view source code as a design document, I have no objection to design
concepts being expressed in a visual DSL. A multi-language project
*always* has extra issues, but if the costs are outweighed by the
benefits, that's just a rational trade-off.
You know, it may seem like an easy fight when you start, but it's
pretty humiliating to be outwitted by a straw man, even if it did have
help :-(
>I've yet to have met a programmer where the function signature
>wouldn't have been enough:-).
Yes, and this is a concern I still have with Doxygen use. I'm still
putting some annotations where I wouldn't have had a plain comment. At
some level, that process has become an end in itself for me.
Whoops.
>There is no one right answer, but in this particular project,
>Rose would have been a lot more helpful than all of the
>Doxygen-like comments.
Well yes - but surely this is just an argument for justifiable
homicide?
> Stephen Horne wrote:
>> On Sat, 01 Aug 2009 18:10:44 +1200, Ian Collins <ian-...@hotmail.com>
>> wrote:
>>
>>> Gerhard Fiedler wrote:
>>>> When I have eight functions each a page long, I don't like them
>>>> inside the declaration. Rips the context apart.
>>>
>>> When I have eight functions each a page long, I know I've done
>>> something wrong!
>>
>> Not necessarily - moving complexity to the call-graph doesn't
>> eliminate it, and some functions really are just do-this then
>> do-that then do-the-other. A comment at the top of each chunk may
>> make more sense than splitting it up.
>
> One or two may be, but eight?
>
>> To me, it suggests an ex-Java or C# programmer who hasn't absorbed a
>> certain key fact about C++.
>
> Or a PHP programmer.
Right, I'm an ex-con programmer... :)
Now seriously, don't you ever write functions a page long? Don't you
ever have a template class with more than a few members? Maybe eight
page-long functions is a bit on the edge, for discussion's sake, but I'm
sure you can get the idea (if you want to, that is :)
Gerhard
Not recently, no.
> Don't you ever have a template class with more than a few members?
Yes.
> Maybe eight
> page-long functions is a bit on the edge, for discussion's sake, but I'm
> sure you can get the idea (if you want to, that is :)
Oh I can, one only has to look at a typical STL header!
--
Ian Collins
>> I've yet to have met a programmer where the function signature
>> wouldn't have been enough:-).
>
> Yes, and this is a concern I still have with Doxygen use. I'm still
> putting some annotations where I wouldn't have had a plain comment.
> At some level, that process has become an end in itself for me.
I think the moment you extract a Doxygen documentation from your
sources, you're actually creating two documents: the source and the
Doxygen documentation, and both need care.
If most of your functions have at least a \brief comment, then when it's
missing, some readers of the Doxygen documentation probably will wonder
whether they're missing something. Whereas if its there, it confirms
that the obvious is all there is.
So I think if you generate such a documentation, it is to a certain
degree an end in itself, or else you wouldn't do it. Even if this end
contributes to the overall end, it is a value in its own right.
Which IMO goes for every documentation, in general for every part of a
project. The art, of course, is to never lose sight of the final end and
keep the balance... :)
Gerhard
> <james.ka...@gmail.com> wrote:
> >On Aug 3, 4:52 pm, Stephen Horne <sh006d3...@blueyonder.co.uk> wrote:
> >> State diagrams, data flow diagrams, entity-relationship
> >> diagrams, class diagrams and all the rest are useful and all
> >> have their place, but as soon as you adopt a specific
> >> methodology and a standardized syntax, you'll end up pedanting
> >> on that instead of the actual design.
> >Why? Do you end up pedanting on C++, rather than the actual
> >program?
> Yes, as does any C++ programmer who wants their program to
> actually compile, let alone work.
Yes. I rather misstated that. (Like you, I'm not sure if
pedanting is the right word, or even if it exists as a word.
But it sounds "right" for what you're explaining.) You do have
to be concerned with a lot of "pedantic" issues in order to get
your code to compile, and to be sure that there is no undefined
behavior even if it compiles.
But UML doesn't require any of that. Typically, such things are
only necessary at the lowest level you write (assembler, if you
implement in assembler, C++ if that's your language, etc.). And
I don't know of any programming language without such issues.
Above that lowest level, however, such problems shouldn't, and
typically don't, occur.
[...]
> If UML dealt with things like the inherited C nasties and
> standard library strangeness, it might well be the kind of
> tool that I'd grab with both hands and never let go. But it
> doesn't.
I'd say you're looking at it backwards. What I like about UML
is that I don't have to be concerned with the pedantic aspects
of C++ when I'm using it. I'm working at a higher level of
abstraction. With some formalisms, but a lot less than are
present at the lower levels.
> I don't object to having illustrations - I only object to
> pedanting over standard-defined notation issues instead of
> getting on with the real work. I object when the process
> becomes an end in itself, rather than the means to an end - a
> distraction from the real issue.
Yes, but that has nothing to do with UML. Obviously, any
process tool can be misused in this way. But it doesn't have to
be, and in the places where I've used Rose, it wasn't; it was
easier to maintain the code using Rose than without.
> >> The best design documentation I've ever had access to is a
> >> subversion repository. Either that, or the
> >> back-of-whatever-scrap-paper-was-handy doodle that somehow
> >> is still the primary reference a year later.
> >The problem with not having such tools (e.g. Rose) is that
> >you use some sort of graphic abstraction anyway. With Rose,
> >it's UML, and it's in the machine, where others can access
> >it, review it, and refer to it later.
> Who says that doodle isn't in the machine? Who says you don't
> use software?
> My "all my own stuff" subversion repository literally contains
> pretty much that. Text files, HTML notes, diagrams, word
> processor files, etc. IMO, any repository should be the same -
> containing everything relevant to the development of the
> project, not just the source code. Being able to see the code
> at some past point is great - but seeing the wider thought
> processes of the time is far better.
> As you say, some silly scrap of paper gets lost, used to wipe
> up a coffee spill, or whatever. But a scan, or a copy using
> some simple diagram or vector drawing tool, is still, in
> essence, the same diagram.
More or less. The scan isn't editable, which makes
modifications more difficult. And vector drawing tools don't
normally ensure coherence, when several drawings are involved.
And neither actually generates any C++.
> Even when it's edited to reflect a design change, it's still
> fundamentally different to something that's been forced to fit
> the conventions of some standard.
You need some sort of conventions if you expect other people to
be able to understand it. UML is fairly loose---about the
minimum necessary for what it tries to express.
> The point is that that ad-hoc diagram is the important one -
> capturing the essential feature of a design as produced at the
> time of the basic idea, using whatever notation expressed the
> idea well, before people have started adding endless details
> and imposing particular notational and methodological
> standards and religious ideals.
A commonly agreed upon notation is essential if other people are
to understand your diagrams. The amount of detail you put in a
UML diagram is up to you. And there's nothing religious about
it; Rose is an effective tool for certain things, but you still
need other types of documentation as well.
[...]
> > // \behavior
> > // Sets the administrative state to the
> > // new value
> I pity you - but this is just the old overcommenting thing.
> Another example of the process becoming an end in itself and
> defeating its own purpose.
But that's exactly what you're objecting to in UML. It has
nothing to do with UML, or Doxygen, or any tool. It's just a
question of the tool being misused.
[...]
> True Doxygen expertise, IMO, is in not being an expert. It
> isn't when you know all the annotations. It's when you don't
> know most of them because you hardly ever need them. Most of
> my methods, for example, have a "\brief" description, often
> (but not always) followed by a detailed description. "\param"
> I use in rare cases, and I don't recall ever using "\return".
Interesting. I think that most of my Doxygen documentation is
in the form of \pre, \post and \return. In a lot of cases, \pre
and \post effectively describe all of the behavior of the
function; in the case of "true" functions (with a return value
other than just a return code), the \return more or less
replaces the \post (and unless otherwise documented, there is an
implicit \post---that the object is unchanged by the function).
That's within the class, of course. There's a fair amount of
documentation outside of the class as well.
[...]
> >There is no one right answer, but in this particular project,
> >Rose would have been a lot more helpful than all of the
> >Doxygen-like comments.
> Well yes - but surely this is just an argument for justifiable
> homicide?
Or better training for management:-).
>I'd say you're looking at it backwards. What I like about UML
>is that I don't have to be concerned with the pedantic aspects
>of C++ when I'm using it. I'm working at a higher level of
>abstraction. With some formalisms, but a lot less than are
>present at the lower levels.
You don't have to pedant all the details of C++ to write comments, or
the initial not-meant-to-compile, not-meant-to-be-even-nearly-complete
drafts.
To use an analogy, there are all sorts of writers guides out there for
people who dream of writing a novel. There's software tools that
prompt for and organise details of characters, settings, events and so
on.
The professional writers most certainly have methods, and maybe a few
even use Writers Cafe or whatever, but it seems that what really works
is the quick draft followed by repeated ruthlessly critical rewrites.
Anything beyond that and ad-hoc notes is a newbies magic non-solution
or the occasional pros personal quirk.
In short, the approach doesn't require different notations. I've
already admitted my error and I won't claim that UML isn't a valid and
appropriate option, but this doesn't mean that a process of quick
drafting then ruthlessly critical rewriting cannot be done in text
files that will eventually to be fed to a compiler.
>> As you say, some silly scrap of paper gets lost, used to wipe
>> up a coffee spill, or whatever. But a scan, or a copy using
>> some simple diagram or vector drawing tool, is still, in
>> essence, the same diagram.
>
>More or less. The scan isn't editable, which makes
>modifications more difficult.
Actually, I have Photoshop and a cheap graphics tablet, and there's
always Windows Paint or similar and a mouse. For that matter, almost
any vector graphics program can put a scan in the background, mask
areas using white rectangles, etc etc.
TortoiseSVN can even show two versions of an image side-by-side or
give you a slider to transition from one to the other.
> And vector drawing tools don't
>normally ensure coherence, when several drawings are involved.
>And neither actually generates any C++.
This is true - but surely, as soon as you ensure coherence between
diagram and source, you have to pedant about the notation of and
details in the diagram? It becomes visual source code, IOW.
>You need some sort of conventions if you expect other people to
>be able to understand it. UML is fairly loose---about the
>minimum necessary for what it tries to express.
Sometimes, more is less. Less familiar, for instance. Everyone
understands a basic bubbles-and-arrows dataflow diagram, for instance,
but how many people have instant familiarity with Ward/Mellor
conventions, or Yourdon conventions, or Mascot conventions? How many
would know that that other arrow style is a control flow, or how a
control flow differs from a normal data flow? How many would know that
that box with open sides is a data store, rather than a normal
process? How many people know that dots and bars at the ends of an
arrow indicate which process is in control of the data flow - who
calls who, or which side of a rendezvous or whatever you're on?
Less freedom, too - you can't improvise your own arrow style for some
application-specific purpose without having to check that you're not
using an already-standards-defined special purpose arrow and therefore
causing confusion, or having pedants tell you "you can't do that -
it's not in the standard" and getting too stressed about your
blasphemy to focus on the design itself.
Consider a state diagram. You have boxes and arrows, write "xxx state
model" at the top, and everyone understands it. Use the UML standard
with it's three-part split boxes and suddenly only the UML-familiar
are confident they know what the different parts express. It's not
just a state model any more - it describes implementation details and
thus references an implicit implementation model which readers need to
be aware of. For example, there's a built-in assumption that the
states relate to a particular class. The first edition of "UML
Distilled" has eight pages describing UML state models (one of the
simplest UML diagram standards), and the first paragraph places
arbitrary limitations on their use seemingly without even noticing -
an abstraction for which a state model applies *MUST* be a class.
Split your boxes into three for some application-specific reason -
maybe every state has three outputs - and, no matter your key or the
explanation that makes sense to everyone else, the UML-familiar
readers will be thrown. And your tool will be very upset, of course.
So yes, you need some kind of conventions - but simpler is better. The
cost of more complex standard is that the extra notations you use are
unfamiliar to lots of readers, while the notations you don't use get
in the way of expressing ideas that the standard didn't anticipate.
>Interesting. I think that most of my Doxygen documentation is
>in the form of \pre, \post and \return. In a lot of cases, \pre
>and \post effectively describe all of the behavior of the
>function; in the case of "true" functions (with a return value
>other than just a return code), the \return more or less
>replaces the \post (and unless otherwise documented, there is an
>implicit \post---that the object is unchanged by the function).
Preconditions and postconditions are easily documented in the detailed
description. I never even looked for those tags. I have no objection
to them - I just happen not to use them myself.
I prefer the 'const' keyword for saying the object is unchanged,
though if you meant side-effects or changes to mutable members, I
agree with the basic point.
> <james.ka...@gmail.com> wrote:
> >I'd say you're looking at it backwards. What I like about
> >UML is that I don't have to be concerned with the pedantic
> >aspects of C++ when I'm using it. I'm working at a higher
> >level of abstraction. With some formalisms, but a lot less
> >than are present at the lower levels.
>
> You don't have to pedant all the details of C++ to write
> comments, or the initial not-meant-to-compile,
> not-meant-to-be-even-nearly-complete drafts.
Agreed. I use that too. I also use HTML, for information that
transcends single files, and is best expressed in text, rather
than graphically. I find, however, that the graphics of UML are
more expressive than plain text when it comes to expressing the
relationships between classes, scenerios, and such.
There is one other aspect, where tools like Rose seem to be in
advance of the text based tools I use. What you're writing
isn't just a rough draft---it's meant to be read and maintained.
And one of the things that has always bothered me with most
forms of documentation is that the "source code" of the
documentation, which is what the maintainer has to deal with,
isn't as clean and neat as the documentation itself---CWeb
sources contain distracting mark-up, Doxygen comments have all
those comment markers, etc. This seems to be less true of Rose,
in which what you see is what you get, with regards to the
documentation. (For the graphics, at least. Not all
documentation and design can be expressed with graphics, and the
integration of text in Rose---or Together---cannot be considered
particularly successful.)
For Doxygen comments, I've written a couple of tools, which work
well with my editor (vim)---when I want to write a comment
(Doxygen or not), I'll hit F1, which changes the mode of the
editor so that the programmy things are turned off. I'll then
write the text as I would in a plain text document, with some
very simple (not very well designed) mark-up. Finally, I'll hit
F2, which pipes the text through my program, formatting it as
comments (Doxygen or not, depending on the options I add), and
puts the editor back into C++ mode. When I want to edit the
comment, I also have a command which converts the text back into
its original text form, more or less; I then edit that, and
reformat it as a comment.
Another aspect in favor of Rose or Together (compared to the
other tools I know) is that they understand much of the
structure. You modify the name of a class, for example, and it
is modified everywhere, in all of the diagrams. Global search
and replace can do a lot of that with a good editor, but it's
not quite as effective.
> To use an analogy, there are all sorts of writers guides out
> there for people who dream of writing a novel. There's
> software tools that prompt for and organise details of
> characters, settings, events and so on.
> The professional writers most certainly have methods, and
> maybe a few even use Writers Cafe or whatever, but it seems
> that what really works is the quick draft followed by repeated
> ruthlessly critical rewrites. Anything beyond that and ad-hoc
> notes is a newbies magic non-solution or the occasional pros
> personal quirk.
> In short, the approach doesn't require different notations.
> I've already admitted my error and I won't claim that UML
> isn't a valid and appropriate option, but this doesn't mean
> that a process of quick drafting then ruthlessly critical
> rewriting cannot be done in text files that will eventually to
> be fed to a compiler.
I don't know how professional novelist write; I suspect it
varies depending on the novelist. (Mozart never wrote anything
out until the final version. Beethovan wrote out endless
preliminary versions.) And I'm not sure it's a valid analogy.
There are too many differences in the product: a program has to
meet very rigorous specifications, for example; it must be
maintained (and thus be maintainable); the design documents
become part of the documentation, etc., etc. A more valid
comparison would probably be with an architect designing a
house, but I don't really know how they work, either. (And even
there, there's no need to document how they came up with the
design for later use.)
> >> As you say, some silly scrap of paper gets lost, used to wipe
> >> up a coffee spill, or whatever. But a scan, or a copy using
> >> some simple diagram or vector drawing tool, is still, in
> >> essence, the same diagram.
> >More or less. The scan isn't editable, which makes
> >modifications more difficult.
> Actually, I have Photoshop and a cheap graphics tablet, and
> there's always Windows Paint or similar and a mouse. For that
> matter, almost any vector graphics program can put a scan in
> the background, mask areas using white rectangles, etc etc.
You're not going to tell me that that's anywhere near as simple
as modifying a UML diagram with Rose:-).
> TortoiseSVN can even show two versions of an image
> side-by-side or give you a slider to transition from one to
> the other.
> >And vector drawing tools don't normally ensure coherence,
> >when several drawings are involved. And neither actually
> >generates any C++.
> This is true - but surely, as soon as you ensure coherence
> between diagram and source, you have to pedant about the
> notation of and details in the diagram? It becomes visual
> source code, IOW.
First, I was principly thinking of coherence within the design
itself. Change the name (or some other characteristic) of a
class, and it changes everywhere, since internally, the system
stores a reference to a description of the class, and not the
visual image.
With regards to coherence between diagram and source, yes. When
you get down to the levels which affect code generation, you
have to be somewhat pedantic. Not quite as much as if you were
writing C++ directly, but almost. But that's no different than
with any other technique---in CWeb, you have to enter the parts
that will end up as C++ source code exactly as C++ source code;
with Doxygen, you're actually writing C++ code. With the other
tools, you also have to be somewhat pedant with respect to the
parts that don't generate C++ code---with Doxygen, to such a
degree that I was motivated to write a tool which takes care of
it for me. I find Rose significantly easier in this regard.
> >You need some sort of conventions if you expect other people
> >to be able to understand it. UML is fairly loose---about the
> >minimum necessary for what it tries to express.
> Sometimes, more is less. Less familiar, for instance. Everyone
> understands a basic bubbles-and-arrows dataflow diagram, for
> instance, but how many people have instant familiarity with
> Ward/Mellor conventions, or Yourdon conventions, or Mascot
> conventions? How many would know that that other arrow style
> is a control flow, or how a control flow differs from a normal
> data flow? How many would know that that box with open sides
> is a data store, rather than a normal process? How many people
> know that dots and bars at the ends of an arrow indicate which
> process is in control of the data flow - who calls who, or
> which side of a rendezvous or whatever you're on?
And how many people are familiar with your personal conventions.
Your argument here is in favor of UML, not against it. UML is
the most widespread standard diagramming language. It is thus
the one most likely to be already known by others.
> Less freedom, too - you can't improvise your own arrow style
> for some application-specific purpose without having to check
> that you're not using an already-standards-defined special
> purpose arrow and therefore causing confusion, or having
> pedants tell you "you can't do that - it's not in the
> standard" and getting too stressed about your blasphemy to
> focus on the design itself.
People do:-). People also invent new words in English, or give
existing words different meanings.
It's all a question of whether you want to be understood or not.
Inventing some new arrow style, or word, for some special use,
is not something to be done lightly, since no one reading the
document will understand it.
> Consider a state diagram. You have boxes and arrows, write
> "xxx state model" at the top, and everyone understands it. Use
> the UML standard with it's three-part split boxes and suddenly
> only the UML-familiar are confident they know what the
> different parts express. It's not just a state model any more
> - it describes implementation details and thus references an
> implicit implementation model which readers need to be aware
> of.
It doesn't have to.
I didn't use state diagrams much in the applications where I
used Rose, but given the way other nodes (classes, etc.) are
handled, I expect that in any diagram, you can mask out the
information irrelevant to that diagram. And you're never
required to enter information that would be irrelevant to all
diagrams.
> For example, there's a built-in assumption that the states
> relate to a particular class. The first edition of "UML
> Distilled" has eight pages describing UML state models (one of
> the simplest UML diagram standards), and the first paragraph
> places arbitrary limitations on their use seemingly without
> even noticing - an abstraction for which a state model applies
> *MUST* be a class.
As I say, I'm not too familiar with state diagrams, but I can't
find this restriction in any of the documentation I have.
Fowler (in UML Distilled, Third Edition) actually mentions three
possibilities: nested switches, the State pattern, and state
tables. (But I don't know what Rose does with them, if
anything.)
> Split your boxes into three for some application-specific
> reason - maybe every state has three outputs - and, no matter
> your key or the explanation that makes sense to everyone else,
> the UML-familiar readers will be thrown. And your tool will be
> very upset, of course.
Throw in enough German words when writing English, and your
reader will become confused. What's the difference?
> So yes, you need some kind of conventions - but simpler is
> better. The cost of more complex standard is that the extra
> notations you use are unfamiliar to lots of readers, while the
> notations you don't use get in the way of expressing ideas
> that the standard didn't anticipate.
UML could be a lot simpler, but generally speaking, you don't
have to use all of the extra features. UML diagrams are only as
complicated as you want to make them.
> >Interesting. I think that most of my Doxygen documentation
> >is in the form of \pre, \post and \return. In a lot of
> >cases, \pre and \post effectively describe all of the
> >behavior of the function; in the case of "true" functions
> >(with a return value other than just a return code), the
> >\return more or less replaces the \post (and unless otherwise
> >documented, there is an implicit \post---that the object is
> >unchanged by the function).
> Preconditions and postconditions are easily documented in the
> detailed description. I never even looked for those tags. I
> have no objection to them - I just happen not to use them
> myself.
Everything can easily be documented in the detailed description.
There are some advantages, however, to using standard
tags---they create a standard formatting, so the reader can
easily identify them.
> I prefer the 'const' keyword for saying the object is
> unchanged, though if you meant side-effects or changes to
> mutable members, I agree with the basic point.
Agreed. I just picked the first example that came to mind of
something that doesn't need explicit documenting, but you're
right, in C++, the language itself documents that. (With
regards to mutable members... they should be an implementation
detail. If the modification of a mutable member means that the
"value" of the object is seen to change by a client, then any
function which does that modification should not be const.
Mutable is for handling internal details, which the client can't
see.)
>> >> As you say, some silly scrap of paper gets lost, used to wipe
>> >> up a coffee spill, or whatever. But a scan, or a copy using
>> >> some simple diagram or vector drawing tool, is still, in
>> >> essence, the same diagram.
>
>> >More or less. The scan isn't editable, which makes
>> >modifications more difficult.
>
>> Actually, I have Photoshop and a cheap graphics tablet, and
>> there's always Windows Paint or similar and a mouse. For that
>> matter, almost any vector graphics program can put a scan in
>> the background, mask areas using white rectangles, etc etc.
>
>You're not going to tell me that that's anywhere near as simple
>as modifying a UML diagram with Rose:-).
A graphics tablet is as simple to use as a pen or pencil. OK, maybe
I'm talking about one of those geeky pens with a ring of
pick-which-colour buttons, but no worse than that.
Photoshop is a very complex program, true, but like you say about
Rose, you don't have to care about all that complexity. If all you
need to do is load a file, erase some stuff, draw some stuff, and
save, that's all you need to know.
And Paint, of course, simply doesn't have the complexity.
Either way, if you want to draw a particular shape, you just draw it.
You don't need to know which icon or menu to use for that shape -
unless, of course, you want a perfect non-freehand version. And that's
no real hassle either. If you can drag a selection box over a group of
icons, you can draw a rectangle in any graphics package.
And not having a graphics tablet is no excuse - a mouse isn't ideal,
but it works.
Seriously, editing a bitmap image is no harder than editing a text
file these days. If you don't need works of art, it's easier - and
easier by far than using a simple diagram editor or vector art
program, so presumably easier than using something like Rose.
What's more, you aren't limited to the notations that the graphics
software designers anticipated.
Where the bitmap approach fails is where a programming language like
Basic fails. It's fine for simple cases, but it breaks down as you
expect it to deal with more and more stuff. The data doesn't have
explicit structure, so the machine can't help you maintain that
structure. But recall the context - this is about that one simple
diagram, originally scribbled on the back of whatever was handy, that
expresses the core idea better than any formalism. Complexity is what
I want to avoid.
>> >And vector drawing tools don't normally ensure coherence,
>> >when several drawings are involved. And neither actually
>> >generates any C++.
>
>> This is true - but surely, as soon as you ensure coherence
>> between diagram and source, you have to pedant about the
>> notation of and details in the diagram? It becomes visual
>> source code, IOW.
>
>First, I was principly thinking of coherence within the design
>itself.
I have already expressed my view that the source code is a design
document. Whether you agree or not, the source code still has to be
maintained - it's still work that needs to be done.
I generally have very few hand-written diagrams like this to worry
about. The diagrams that get a bit more numerous are either
Doxygen-generated, or else handwritten GraphViz dot files. The latter
can be handled using search-and-replace as with the source code,
though I don't suppose that's an issue for most people - I just happen
to like dot a lot, and to be dealing with a lot of simple state
diagrams just recently.
Those simple state diagrams are very much like those found in most
automata theory books, though with a few application-specific tweaks.
Nothing like UML state diagrams, IOW.
>With regards to coherence between diagram and source, yes. When
>you get down to the levels which affect code generation, you
>have to be somewhat pedantic. Not quite as much as if you were
>writing C++ directly, but almost. But that's no different than
>with any other technique---in CWeb, you have to enter the parts
>that will end up as C++ source code exactly as C++ source code;
>with Doxygen, you're actually writing C++ code. With the other
>tools, you also have to be somewhat pedant with respect to the
>parts that don't generate C++ code---with Doxygen, to such a
>degree that I was motivated to write a tool which takes care of
>it for me. I find Rose significantly easier in this regard.
Yes - after the error I started out making, I'm not arguing that Rose
is a bad option - just that it isn't profoundly different to editing
source code. UML is acting as a visual domain-specific programming
language, with all the advantages and disadvantages you'd expect.
>And how many people are familiar with your personal conventions.
With ad-hoc conventions, you don't expect other people to be psychic -
as I have already said many times, you include a key/legend.
>Your argument here is in favor of UML, not against it. UML is
>the most widespread standard diagramming language. It is thus
>the one most likely to be already known by others.
I wonder which is the most healthy burger in McDonalds? That *MUST* be
a healthy food, eh!
"Most widespread" doesn't mean much. And in any case, I disagree - the
most widespread standard is to use a key to explain anything that
isn't immediately obvious.
>People do:-). People also invent new words in English, or give
>existing words different meanings.
>
>It's all a question of whether you want to be understood or not.
>Inventing some new arrow style, or word, for some special use,
>is not something to be done lightly, since no one reading the
>document will understand it.
And still, you ignore the simple concept of a key.
Perhaps you have been the victim of someone who claims that a 50,000
line DTD means their XML document is more self-describing than it was
when it was merely easily understood by any human or higher ape?
What I have in mind has much more in common with the keys you see on
every pie chart, bar chart etc. It's not an esoteric practice - it's
normal. In the wider world, it's expected - it's *NOT* having a key
that normally draws criticism for obvious reasons.
Or maybe my mistake is using the word "key" instead of "legend"?
As for inventing special meanings being something "not to be done
lightly", every project that I (and you) have ever worked on has
invented large numbers of specialised word meanings. Every single
variable name, function name, type name, file name - they all have
more specialised meaning within the project than that defined for the
words in the English language, and usually even more specialised than
within the domain-specific jargon.
>> Split your boxes into three for some application-specific
>> reason - maybe every state has three outputs - and, no matter
>> your key or the explanation that makes sense to everyone else,
>> the UML-familiar readers will be thrown. And your tool will be
>> very upset, of course.
>
>Throw in enough German words when writing English, and your
>reader will become confused. What's the difference?
We're talking about simple diagrams with simple keys here. You'll have
no trouble being understood - unless someone was expecting UML. Even
in a room full of UML fanboys, you'll be understood so long as they
don't assume the diagram is UML - and so long as you don't get that
one-in-a-hundred who is obsessive.
The "German" of your analogy is UML.
Expecting people to notice and read a key/legend is in no way
comparable to expecting people to know a whole language like German,
or like the smaller but still textbook-sized UML. And UML is still
evolving, too - there are two major revisions and several minor
revisions already.
Will UML 1.0 be as comprehensible as you think in 10 or 20 or 30 years
time? When you're trying to work with some ancient printout of a
design you can no longer load into Rose because UML and Rose have both
moved on and Rose itself has been sold on to other companies 2 or 3
times and, in any case, the files went missing maybe a decade ago with
no-one noticing - will you be confident what those annotations mean?
Will you even be sure whether that diagram is in UML 1.0, or 1.1, or
2.0, or 2.1 or whatever? Might UML itself even be a distant memory?
Once, before I had easy internet access, I needed to read a Mascot
diagram and thanked God for old boxes full of crap because I had no
other way to find out what the once-familiar conventions meant.
Of course Mascot always was an obscure niche thing, whereas UML is
widespread, isn't it?
"In practice, people often draw diagrams with the symbols provided by
their CASE tool, but without the meanings those symbols are intended
to provide."
http://en.wikipedia.org/wiki/Unified_Modeling_Language#Criticisms
Maybe genuine UML isn't as widespread as you think.
Of course this UML abuse is essentially what I argued can't happen - I
said you can't use the notation for your own application-specific
meaning because it has another standards-defined meaning that gets in
your way. If the Wikipedians can be trusted on this, people are
apparently just going ahead and using UML notations with ad-hoc
meanings, perhaps out of ignorance of the UML-specific meaning,
perhaps because they know but don't care.
Does this mean I'm wrong in principle? I don't think so. If people are
doing ad-hoc diagrams with UML box and arrow shapes, they are either
being understood or not - either way fit's my main point about ad-hoc
diagrams. If UMLs main contribution is a bunch of meaning-free
box-shapes, it has failed.
Also, if UML is commonly being misused, maybe we should revisit that 3
week training course issue.
>> So yes, you need some kind of conventions - but simpler is
>> better. The cost of more complex standard is that the extra
>> notations you use are unfamiliar to lots of readers, while the
>> notations you don't use get in the way of expressing ideas
>> that the standard didn't anticipate.
>
>UML could be a lot simpler, but generally speaking, you don't
>have to use all of the extra features. UML diagrams are only as
>complicated as you want to make them.
In the post you're replying to, I never claimed that you have to use
all the UML features. I explicitly said that they can get in the way
even when you *don't* use them, because you can't use the notation for
anything else more relevant to your application.
Of course that has been somewhat qualified by what I said a few
paragraphs earlier in this post. The UML standard can't seriously be
considered a limit to anyones freedom if ignoring the rules is
widespread. It does emphasise the need for that legend, of course.
>Everything can easily be documented in the detailed description.
>There are some advantages, however, to using standard
>tags---they create a standard formatting, so the reader can
>easily identify them.
And an arbitrary separation of concerns that are often naturally
closely coupled, assuming your functions tend to be small.
Swings and roundabouts, IMO. I'd have an option on horses for courses,
but constantly switching styles from one function to the next would be
too annoying.
>(With
>regards to mutable members... they should be an implementation
>detail. If the modification of a mutable member means that the
>"value" of the object is seen to change by a client, then any
>function which does that modification should not be const.
>Mutable is for handling internal details, which the client can't
>see.)
Memoizing of results can an important design feature in cases where
there are performance requirements. It potentially turns an O(n)
algorithm into an O(n^k) algorithm or worse. If you use mutable for an
optimisation that you consider an "implementation detail", perhaps
you're doing premature optimisation.
Collecting metrics is another reason for using mutable. Again, I don't
view this is just an "implementation detail".
Not that I use mutable much, except as a quick hack to get
semi-refactored versions to run regression tests. It seems silly to
argue about the use of something I don't use, but what the hell - it's
exactly what I'm doing WRT UML anyway ;-)
Point is, while I'm sure there are cases where mutable really is an
implementation detail, I'm equally sure that there are cases where it
isn't.
Which is all true, but it is still a lot simpler to drag and
drop an icon to where ever you want it, and get the design
completely done, than to figit with drawing four lines. (I've
done it both ways---Rose is at least an order of magnitude
simpler.)
> Seriously, editing a bitmap image is no harder than editing a
> text file these days. If you don't need works of art, it's
> easier - and easier by far than using a simple diagram editor
> or vector art program, so presumably easier than using
> something like Rose.
> What's more, you aren't limited to the notations that the
> graphics software designers anticipated.
Which isn't necessarily an advantage. Arbitrary graphics are
like invented words in a document. Generally, you want to avoid
them.
> Where the bitmap approach fails is where a programming
> language like Basic fails. It's fine for simple cases, but it
> breaks down as you expect it to deal with more and more stuff.
> The data doesn't have explicit structure, so the machine can't
> help you maintain that structure. But recall the context -
> this is about that one simple diagram, originally scribbled on
> the back of whatever was handy, that expresses the core idea
> better than any formalism. Complexity is what I want to avoid.
The complexity is there, in the application. You can't avoid
it, you can only organize it in a way to make it masterable.
> >> >And vector drawing tools don't normally ensure coherence,
> >> >when several drawings are involved. And neither actually
> >> >generates any C++.
> >> This is true - but surely, as soon as you ensure coherence
> >> between diagram and source, you have to pedant about the
> >> notation of and details in the diagram? It becomes visual
> >> source code, IOW.
> >First, I was principly thinking of coherence within the design
> >itself.
> I have already expressed my view that the source code is a
> design document. Whether you agree or not, the source code
> still has to be maintained - it's still work that needs to be
> done.
I don't disagree. I prefer for the low level documentation to
be in the same file as the code, too. But such documentation
doesn't cover everything. You need higher level documentation
as well.
> I generally have very few hand-written diagrams like this to
> worry about.
That sounds like you are either doing very simple systems, or
aren't doing enough up front design. In the applications I work
on, several hundred classes is pretty much a minimum. And you
need a fair amount of higher level "documentation" to figure out
what those classes should be.
[...]
> Those simple state diagrams are very much like those found in
> most automata theory books, though with a few
> application-specific tweaks. Nothing like UML state diagrams,
> IOW.
UML isn't necessarily the tool for everything. I probably
wouldn't use it if all I had were state diagrams (but that
probably only applies to very small, embedded systems). On the
other hand, the UML state diagrams I've looked at on the network
look very much like the ones I've seen in books about automata
theory.
> >With regards to coherence between diagram and source, yes.
> >When you get down to the levels which affect code generation,
> >you have to be somewhat pedantic. Not quite as much as if
> >you were writing C++ directly, but almost. But that's no
> >different than with any other technique---in CWeb, you have
> >to enter the parts that will end up as C++ source code
> >exactly as C++ source code; with Doxygen, you're actually
> >writing C++ code. With the other tools, you also have to be
> >somewhat pedant with respect to the parts that don't generate
> >C++ code---with Doxygen, to such a degree that I was
> >motivated to write a tool which takes care of it for me. I
> >find Rose significantly easier in this regard.
> Yes - after the error I started out making, I'm not arguing
> that Rose is a bad option - just that it isn't profoundly
> different to editing source code. UML is acting as a visual
> domain-specific programming language, with all the advantages
> and disadvantages you'd expect.
It is and it isn't. It can generate source code, and if you're
using it for that, then you do have to be just as precise as
when writing source code---it can't invent things that you don't
tell it. But the abstraction generally rests at a much higher
level, with a lot of this "precision" hidden.
[...]
> >Your argument here is in favor of UML, not against it. UML is
> >the most widespread standard diagramming language. It is thus
> >the one most likely to be already known by others.
> I wonder which is the most healthy burger in McDonalds? That
> *MUST* be a healthy food, eh!
We're talking about well known, not healthy, here.
> "Most widespread" doesn't mean much.
It does when you're talking about conventions used to
communicate with other people.
> And in any case, I disagree - the most widespread standard is
> to use a key to explain anything that isn't immediately
> obvious.
That means extra effort for the people who have to read it.
> >People do:-). People also invent new words in English, or
> >give existing words different meanings.
> >It's all a question of whether you want to be understood or
> >not. Inventing some new arrow style, or word, for some
> >special use, is not something to be done lightly, since no
> >one reading the document will understand it.
> And still, you ignore the simple concept of a key.
No, but it implies extra effort. Sometimes, the added
expressivity is worth the effort, but most of the time, it's
just extra baggage.
[...]
> As for inventing special meanings being something "not to be
> done lightly", every project that I (and you) have ever worked
> on has invented large numbers of specialised word meanings.
> Every single variable name, function name, type name, file
> name - they all have more specialised meaning within the
> project than that defined for the words in the English
> language, and usually even more specialised than within the
> domain-specific jargon.
That's why we have documentation:-).
Seriously, of course, we don't choose variable names randomly.
People who understand English (substitute the working language
of the project here) should have a pretty good idea of what the
variable contains from its name, without a key or a legend.
Anyway, you obviously don't like UML. All I can really say is
that I've worked on a lot of different projects, using a lot of
different methodologies, and UML has been one of the best in
terms of programmer productivity. It works, and most well run
shops use it.
e.g. of course you don't need to know the whole of UML. Yet writing a
simple legend is a according to you a terrible burden, meaning either
the readers of your diagrams are expected to know every UML feature
you use, or else they have to go looking for a reference to explain
it.
So according to you, reading a simple legend that's right there on the
page is a burden, but having to find and search a book isn't?
Yes and no. It's the same as with C++: you don't need to know
all of C++ in order to write good C++ code; if you read code
which uses some feature you don't know, however, you have to
learn it, at least passively. Which improves your knowledge of
C++, a commonly used tool. In this regard, UML is no different.
Except that much of it, especially the more widely used parts,
are pretty intuitive---I only read my first book about it a year
or so ago, after I'd already used it successfully in several
projects. (When I learned OO programming, of course, UML didn't
exist---it was all Booch cloud diagrams. But probably, some of
my knowledge of cloud diagrams did help in "intuitively"
understanding UML.)
Anyway, I'm not going to argue with you. In the end, we're both
really presenting a posteriori arguments: I originally used UML
because management introduced the use of Rational Rose in a
project, and it made a significant improvement in programmer
productivity. Having seen how much it improved productivity, I
tried to determine why, and present my conclusions as "reasons",
but the real motivation behind my choice is the fact that using
Rational Rose very significantly improved productivity. In
several different projects.
>Anyway, I'm not going to argue with you. In the end, we're both
>really presenting a posteriori arguments:
Except I already admitted my error. I agreed that UML is valid, and
stated that I was fighting a strawman. You could have accepted your
victory gracefully days ago. It seems that wasn't enough.
You claim UML isn't a religion, yet it seems to me like your kneejerk
reaction is to defend against any claim that UML isn't the one true
way.
I remember our other big argument in this group. As I recall, we
reached the point where I was arguing that an object has one type and
one layout, fixed on instantiation, hopefully (but not necessarily)
related to the type of pointers and references that point to it. You
were repeatedly denying that, which is pretty odd given that the
standard typeid function is used to identify at run-time the exact
type of the object, as determined by its original instantiation, from
which you can determine its exact memory layout.
In that case, it was me who decided that things had gone on too long.
After you claim essentially that an engine is equal to a car because a
car contains an engine, guess what else you said...
: In other words, you've lost the argument, so you're taking your
: ball and going home.
Far from true then, but now, yes - I agree - you should take your ball
and go home.