Topic: Programming in an embedded environment, was problems with locale and its facets


Author: 1xx754.273x@compuserve.com (Martin Aupperle)
Date: 1998/07/01
Raw View
On 25 Jun 98 23:27:51 GMT, Darron Shaffer <darron.shaffer@beasys.com>
wrote:

[ excessive quoting snipped ]

>
>Now code that tries to ignore the error code must try harder.  If you
>use an ErrorCode class as described by J. Kanze it becomes even more
>difficult.
>

Yes. But I do not want to check error codes at all - for reasons I
gave in another posting. And, BTW, it does not solve the problem
outlined in my original posting. If you have something like

  m+= f();

it simply is not a good idea to return an error code like -1 or so.
And believe me: in *large* programs with many developers, these things
cost more than you believe.
Changing the signature of f to something different can help you find
all the occurences of f with the help of the compiler - but developers
in other departments just simply rename all calls to f to the new name
without rethinking the code. Tight schedule, other more severe
problems, we all know that. AND - they get rewarded for delivering a
"workable product" to the field test in time - not a bug free product.
Let the field find out about the problem and write a SPR - that's what
these guys are paid for.

>Exceptions have thier uses, but other styles of coding can provide
>many of the same benefits.
>

I disagree. Return codes are inferior, even if you force their
checking by (IMHO ugly syntax that distracts from the intended
behavior and makes code hard to red). My two favorite reasons are
1. the situation above
2. errors in operators, like range errors in array -operator  [].

Martin


------------------------------------------------
Martin Aupperle 1xx754.273x@compuserve.com
(replace x with 0 - fight spamming)
------------------------------------------------


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Darron Shaffer <darron.shaffer@beasys.com>
Date: 1998/06/25
Raw View
1xx754.273x@compuserve.com (Martin Aupperle) writes:

] On 23 Jun 98 04:58:51 GMT, kanze@gabi-soft.fr (J. Kanze) wrote:
]
]
] >...  The major argument I hear for exceptions is
] >that it is able to reuse cleanup code in existing destructors.  And that
] >putting such cleanup code in the destructors generally results in
] >cleaner code than the traditional solutions anyway.
] >
] There is more than that. Assume the following situation:
]
] There is a given function f with the following header
]
]     //-- f gets the number of children in the given family.
]     //
]    int f( const char* familyName );
]
] and code like
]
]   ...
]   n += f( name );
]   ...
]
] All fine. I have thousands of such constructions  in legacy code we
] must deal with.
] Now, some years later, they decided to have f report the situation
] that a name was not found instead of simply aborting the program. They
] are suspicious about new language features like exceptions and want
] traditional handling of errors with return codes. f is changed to
] return -1 (and more codes <0 )in case of errors.
] Unfortunately, not all users of f noticed the change and in turn,
] sometimes n is calculated wrong.
]
] *VERY * difficult to find in a 200.000 line program with >5
] departments working on different parts of the software.
]
] IMHO, the really interesting part of exceptions isthat I know that
] after
]
]   k = f();
]
] k *IS VALID*  or the program would not reach the next statement.
]
] >intelligent use of error codes is actually superior.  (On one project,
] >we used a ReturnCode class which aborted if the destructor was called
] >before the status was read.)
]
] How can that avoid the problems in the above scenario?
]

When you change the behavior of your function f() in such a
fundamental way, you should change its  effective "signature" in a
noticable way.  I use signature in quotes, since I mean more here than
the standard.

One way of changing a functions effective signature is to have it
throw an exception.

If exceptions are not desireable, it must be changed in another way
that will force users to use the new coding style -- perhaps:

from:
 int f();

to:
 pair<int, ErrorCode> f();

Now code that tries to ignore the error code must try harder.  If you
use an ErrorCode class as described by J. Kanze it becomes even more
difficult.

Exceptions have thier uses, but other styles of coding can provide
many of the same benefits.

--
 __  __  _
 _ ) ___ _\   Enterprise Middleware Solutions Darron J. Shaffer
 __) __    \  BEA Systems Inc.   Sr. Software Engineer
              17101 Preston Rd   darron.shaffer@beasys.com
              LB# 115, Ste 260    Voice: (972) 738-6137
              Dallas, TX 75248    Fax:   (972) 738-6111
       http://www.beasys.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Ross Smith" <ross.s@ihug.co.nz>
Date: 1998/06/24
Raw View
J. Kanze wrote ...
>Mike Davies <mike_davies@noco.demon.co.uk> writes:
>
>|>  The detail is inessential using exceptions because as I say above
you
>|>  only need to write the exception producer & exception handler, not
all
>|>  the reporting code in between.
>
>You don't need to write the error reporting code, but you do need to
>prove that clean up correctly takes place.  Could you please cite some
>refereed articles which explain how to prove this in the face of
>arbitrary program flow.

I think the problems people like James Kanze have with exceptions vs.
proofs stem from the "if all you have is a hammer, every problem looks
like a nail" syndrome. In procedural programming, program proof
obviously depends on detailed flow analysis. But C++ is not (primarily)
a procedural language, and I think the assumption that procedural proof
methods are the One True Way is mistaken.

The way to handle program analysis in the presence of exceptions,
virtual functions, and the like is to stop thinking in terms of flow of
control and start thinking in terms of invariants. "Object X is
constructed in function f(); therefore, given that f() exits (whether by
return or exception is irrelevant), we know that X's destructor has been
called. Given that object X's destructor has been called, we know that
object Y is in state Z..." And so on.

--
Ross Smith ................................... mailto:ross.s@ihug.co.nz
.............. The Internet Group, Auckland, New Zealand ..............
  "Remember when we told you there was no future? Well, this is it."
                                                        -- Blank Reg
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: 1xx754.273x@compuserve.com (Martin Aupperle)
Date: 1998/06/24
Raw View
On 23 Jun 98 04:58:51 GMT, kanze@gabi-soft.fr (J. Kanze) wrote:

>Having written correct code in C, Pascal and Assembler (not to mention
>snippets of Fortran, Basic and Cobol), as well as C++ and Java:
>
>1. Correct code can be written in any language.  You just have to want
>to.
>
>2. Exceptions (as in C++ and Java) greatly simplify error reporting.
>They add other complexities -- the most serious is, IMHO, the
>"invisibility" of the program flow paths.
>
IMHO, this "invisibility" is one of the nice things in C++. For
example, the implicit (and therefore invisible) call of the
destructor when an object "goes out of scope" can be used to such
clever things like auto_ptr.
Another topic are type conversions that can be performed implicitely,
like in string s = "asdf", or copy construction.

Sure, these properties are often the reason for ineficient programs,
because a inexperienced programmer does not see what goes on behind
the scenes of his program. Most programmers now know that passing an
object by value might not be the best decision.

Im am sure that the same will happen with exceptions. There will be
dos and dont's exactly as in  the other areas.

>This is manifestly false.  The major argument I hear for exceptions is
>that it is able to reuse cleanup code in existing destructors.  And that
>putting such cleanup code in the destructors generally results in
>cleaner code than the traditional solutions anyway.
>
There is more than that. Assume the following situation:

There is a given function f with the following header

    //-- f gets the number of children in the given family.
    //
   int f( const char* familyName );

and code like

  ...
  n += f( name );
  ...

All fine. I have thousands of such constructions  in legacy code we
must deal with.
Now, some years later, they decided to have f report the situation
that a name was not found instead of simply aborting the program. They
are suspicious about new language features like exceptions and want
traditional handling of errors with return codes. f is changed to
return -1 (and more codes <0 )in case of errors.
Unfortunately, not all users of f noticed the change and in turn,
sometimes n is calculated wrong.

*VERY * difficult to find in a 200.000 line program with >5
departments working on different parts of the software.

IMHO, the really interesting part of exceptions isthat I know that
after

  k = f();

k *IS VALID*  or the program would not reach the next statement.


>So what does being punctilious about dealing with errors have to do with
>exceptions?  A programmer supposes an error cannot occur, so he doesn't
>test the case.  No exception, no error code.  A programmer supposes that
>a given function cannot generate an error, so he doesn't check the error
>code, or he doesn't clean up in case of an exception.

The difference is who does what. In case of error codes, the client
must explicitely clean up. In case of exceptions, the service must
provide for cleanup. The situation is comparable to guaranteed
initialization and finalization with constructors and destructors. I
always can provide an explicit init- and destroy-function and require
my clients to call it. But they can forget it. Better solution is to
have the service provide for it automatically. The same argument is
true for error handling: Even if the client "supposes an error cannot
occur, so he doesn't test the case",  I want the necessary cleanup to
take place. Of course, I have a general-takes-all-not-handled-so-far
exception handler in my code.

>intelligent use of error codes is actually superior.  (On one project,
>we used a ReturnCode class which aborted if the destructor was called
>before the status was read.)

How can that avoid the problems in the above scenario?


------------------------------------------------
Martin Aupperle 1xx754.273x@compuserve.com
(replace x with 0 - fight spamming)
------------------------------------------------


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: kanze@gabi-soft.fr (J. Kanze)
Date: 1998/06/23
Raw View
Mike Davies <mike_davies@noco.demon.co.uk> writes:

    [I've changed the subject, since this really has nothing to do with
    locale and facets any more...

    I'd also like to point out that most of this article is concerned
    with exceptions in safety-critical code.  In this regard, I'd like
    to insist that 1) this is irrelevant to the argument for or against
    EC++, and 2) that my arguments against exceptions here concern only
    safety-critical code -- I don't want them to be taken as an argument
    against exceptions in general.  (I'm still not totally decided in
    general, but the arguments presented by me here are far too dogmatic
    and too strict to apply to general code.]

|>  In article <6m6i4q$7k1$1@nnrp1.dejanews.com>, jkanze@otelo.ibmmail.com
|>  writes
|>
|>  >> >: >In this case, you are simply wrong.  In hi-rel code, exceptions are
|>  >> >: >generally banned, because proving exception safety is too difficult.
|>  >> >
|>  >> >: No, I don't agree. It is completely trivial to make C++ code exception
|>  >> >: safe : compile all modules with exceptions enabled and use the exception
|>  >> >: enabled version of the library. Then wrap the contents of main() in a
|>  >> >: try...catch block.
|>  >> >
|>  >> >What James Kanze probably meant is that it is difficult to ensure
|>  >> >that all relevant cleanup was being made, not that it is difficult
|>  >> >to ensure that an exception does not escape from main().
|>  >>
|>  >> That ain't what he said.
|>  >
|>  >That's exactly what I said.  What do you think "exception safety"
|>  >means?
|>
|>  You are not making the distinction between exception safety (trivial in
|>  C++ , hard in other languages like C for example) with resource
|>  (de)allocation (hard in any language, but provided better for in C++
|>  than in for example C)

Having written correct code in C, Pascal and Assembler (not to mention
snippets of Fortran, Basic and Cobol), as well as C++ and Java:

1. Correct code can be written in any language.  You just have to want
to.

2. Exceptions (as in C++ and Java) greatly simplify error reporting.
They add other complexities -- the most serious is, IMHO, the
"invisibility" of the program flow paths.

Earlier in this thread, it was stated that that all you have to do to
write exception safe code is to wrap the contents of main() in a
try...catch block.  This attitude seems a bit naive to me, given the
number of articles in C++ Reports or the discussions in
comp.lang.c++.moderated about the problems of exception safety.
(Interestingly enough, it is mainly the comments of such critics as Tom
Cargill or Herb Sutter that have convinced me that it might be possible
to use exceptions in normal code.  They level of detail in the problems
they raised, along with the answers by such people as Keven Hopps, have
gone a long way in assuring me that the real problems have been
addressed.  Not enough for safety-critical programs, but enough for many
applications.)

|>  ...snip...
|>
|>  >  Handling errors is difficult, period.  Exceptions
|>  >make reporting errors simpler -- they do not have any effect on detecting
|>  >them nor on handling them.
|>
|>  Not so. Exceptions make handling errors easier than using error codes.

Exceptions make propagating errors easier than using error codes.  They
also make sloppy cleanup "easier", since you can just jump from the
point of error detection to the point of error handling -- the
propagation is automatic.

|>  This is because you only have to write the code to handle the error at
|>  two points : the point where you detect the errror, and the point where
|>  you deal with it.

This is manifestly false.  The major argument I hear for exceptions is
that it is able to reuse cleanup code in existing destructors.  And that
putting such cleanup code in the destructors generally results in
cleaner code than the traditional solutions anyway.

All of which is true for C++ -- the use of finalization is almost as
much a characteristic of C++ as the use of parentheses is for Lisp.  But
it doesn't address the basic consideration of provability.

|>  If you use function return codes then every function has to supply code
|>  to handle all the error codes (either pass the error code up the chain
|>  or deal with the error) that can be returned by *any* function beneath
|>  it.

And if you use exceptions, you must verify at all function calls that
cleanup will be properly handled in case of an exception.

|>  In any case the fact that reporting errors is easier in C++ is a
|>  convincing reason for choosing the language on its own. I'm sure we're
|>  in agreement that SW reliability will improve if programmers become more
|>  punctilious about dealing with errors.

So what does being punctilious about dealing with errors have to do with
exceptions?  A programmer supposes an error cannot occur, so he doesn't
test the case.  No exception, no error code.  A programmer supposes that
a given function cannot generate an error, so he doesn't check the error
code, or he doesn't clean up in case of an exception.  In this case, an
intelligent use of error codes is actually superior.  (On one project,
we used a ReturnCode class which aborted if the destructor was called
before the status was read.)

|>  >Exceptions also introduce unexpected program flow in your program.  What
|>  >the effect of this is depends on many things, but it is never positive.
|>
|>  You do not make the distinction between unexpected program flow and
|>  implicit program flow.
|>  The implicit program flow produced by exceptions *is* advantageous IMO
|>  because it allows the main function performed by the piece of software
|>  to be performed without distracting the programmer/maintainer with a
|>  pile if inessential detail.

I think that this is where we differ.  I don't consider cleaning up in
case of a premature return because of an error an "inessential detail".

|>  The detail is inessential using exceptions because as I say above you
|>  only need to write the exception producer & exception handler, not all
|>  the reporting code in between.

You don't need to write the error reporting code, but you do need to
prove that clean up correctly takes place.  Could you please cite some
refereed articles which explain how to prove this in the face of
arbitrary program flow.

|>  >Whether the negative effect fo the unexpected program flow outweighs the
|>  >positive effect of the simpler error reporting depends on your application,
|>  >your style, and probably partially just on personal taste.
|>
|>  I think that entangling essential application code in strings of error
|>  handling if/then or switch statements is more than a question of
|>  personal taste, I think it is a question of good programming practice.

Correct.  In good programming practice, it is essential to make it clear
when and where clean up are taking place, so that anyone can see that it
DOES take place.  I'm gradually beginning to believe that this can be
done successfully with exceptions, at least sufficiently well for
typical applications.  I'm not yet convinced enough, however, to trust
my life with it.

|>  >At the level of "depends on your application": applications where a
|>  >programming error is simply not acceptable, regardless of price, use
|>  >somewhat elaborate methods of program proof.  Most of the generally known
|>  >methods require single entrance/single exit.  (As has been pointed out
|>  >to me, there have been papers concerning program proofs in other contexts,
|>  >but the work is little known, and the techniques are not generally used.)
|>  >This means that *anything* that does not have single entrance/single exit
|>  >is too expensive, by definition, for the application.
|>
|>  C++ exception handling *is* single exit. The stack is unwound as if all
|>  the functions between the detection of the error and it's handler had
|>  wrapped the rest of theircode in an "if (no_error)" statement. This is
|>  in general how you will pass back an error code that you are not going
|>  to to handle in a given function anyway !

I find your definition of "single exit" surprising.  It doesn't conform
to the definition I've read elsewhere.  (My use is based on the works of
Dijkstra and Hoare, amongst others.)

|>  >Note that in general, anything that results in program flow that is not
|>  >immediately apparent is also out.  Also, rigorous program proof is very
|>  >expensive, with the cost rizing exponentially with the size of the program,
|>  >so such programs are very small.
|>
|>  Reduce the amount of written code further then, by using the exception
|>  handling features of C++ to eliminate the (potentially error prone) hand
|>  production of error reporting code :-)

The question isn't the number of lines of code; the question is the
actual functionality.  Reduce the functionality, and you increase the
probability of correctness.  (Which is, in itself, sort of an argument
for using a subset of C++.  Although not really -- the real argument is
to isolate the critical parts, preferably on a separate processor.)

|>  ...snip...
|>
|>  >I don't think the argument is really whether a subset is useful or not.
|>  >It is whether that subset should be standardized, or perhaps more correctly,
|>  >to what degree that subset should be standardized.  On this, reasonable
|>  >people may differ, and there is no absolute answer.  I find that just
|>  >"standardizing" for myself is not sufficient, but I don't think that
|>  >EC++ should become anything like an ISO standard, either.  The current
|>  >status of EC++ is, however, within the range I would consider acceptable.
|>  >That's all.
|>
|>  The point that I make is that there is no need for EC++ at all. Also it
|>  has features missing from it that I am trying to show are vital for
|>  embedded programmers. In particular exception are IMO important for
|>  people designing safety-critical systems.

They may be important in your opinion, but most safety-critical systems
I've seen have banned exceptions, despite their being available in the
language used (usually Ada).

--
James Kanze    +33 (0)1 39 23 84 71    mailto: kanze@gabi-soft.fr
GABI Software, 22 rue Jacques-Lemercier, 78000 Versailles, France
Conseils en informatique orient   e objet --
              -- Beratung in objektorientierter Datenverarbeitung
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]