comp.lang.ada
 help / color / mirror / Atom feed
From: Robert Dewar <robert_dewar@my-deja.com>
Subject: Re: Exiting from a function or procedure
Date: 2000/04/22
Date: 2000-04-22T00:00:00+00:00	[thread overview]
Message-ID: <8ds3qe$q2d$1@nnrp1.deja.com> (raw)
In-Reply-To: sg2adl5pl6e8@corp.supernews.com

Well first of all let's start with your last statement:

> It does give me a warning, but some thing do happen to
> some C/C++ compilers so i didn't bothered in that message

Big mistake!  Never ignore warnings from GNAT.  They almost
always point to something that is wrong, and if you don't
understand them, you should get someone to help you.  Here
is a cleaned up version of your function:

  function "+" (Izq, Der:  in Term) return Term is Aux :
    Term; Error_Suma :  exception;

  begin
    if (Izq.Exponente = Der.Exponente) then
      Aux.Coeficiente := Izq.Coeficiente + Der.Coeficiente;
      Aux.Exponente   := Izq.Exponente;
      return Aux;
    else
      raise Error_Suma;
    end if;

  exception
    when error_suma =>
      Put(" ERROR !!!");
  end "+";

Now when you compile that, you get:

  20.  Put(" ERROR !!!");
       |
       >>> warning:  "return" statement missing following
           this statement
       >>> warning: Program_Error may be raised at run time

and indeed this warning is 100% accurate, and points to the
serious bug in your function.  if the line ERROR is printed,
then indeed Program_Error will be raised, and it is pretty
likely (I would guess 100% if you are a beginner) that this
was NOT intentional.

So NEVER EVER ignore warnings, consider them as errors.  In
fact you might want to use -gnatwe so the compiler will
treat them as errors enforcing this discipline.

The particular problem is that a function MUST terminate
with a return statement for ALL possible excecution paths,
and clearly your function disobeys this rule for the case
where an exception is raised.  We will address the fix
below.

But before we do, several style comments on your program,
illustrated by the clean up above.

a) indent properly, using standard style, you indented a bit
but in an inconsistent manner and indentation is one thing
that is pretty uniform in Ada, because the RM indicates a
strong recommendation for indentation.

b) use upper/lower case for identifiers as I have done
above, this is not required, but again is very much the most
common Ada standard.  There are other acceptable
capitalization styles used sometimes in Ada, but all lower
case is NOT one of them.  So get rid of that unwelcome C
habit!

c) Use a bit more white space to let the code breathe.  This
is personal taste, but again is pretty standard Ada style.

d) Repeat the name of the function on the end line

e) don't put unnecessary parentheses around expressions. In
particular avoid doing this for conditionals, that's another
C habit that need not be imported into Ada.

Those comments are style comments reflected in the cleaned
up code above.  Now for some more extensive programming
comments.

a) use comments.  Students often get into the appalling
habit of writing code first and commenting it later.  That
is terrible for three reasons:

  1. You don't get into the life long habit of always writing
  comments and if you don't get into that habit your code will
  NEVER be well documented.

  2. Going back and adding documentation later works for
  trivial programs but does not scale up, you simply cannot do
  this on large programs

  3. If you have no comments in the code as you write it, it
  makes it much harder for people to help (if you were one of
  my students I would refuse to help at all, because I would
  have told you in advance that you had better not ever show
  me uncommented code, since I won't help, but I will note it
  down and take off points for the assignment, and my TA's are
  instructed the same way :-)

b) use decent names for things, not abbreviations.  I cannot
even guess what Izq means.  One might guess that Der is
deriviative, but if so, then spell it out. It's a bit more
work to write, but in Ada, the cardinal rule is to write
code that can be easily read. A decent editor that does
name completion can help if you are a slow typist :-)

c) Perhaps this is jumping a bit far from what you know, but
likely the better code for the two assignments is

   Aux := (Coefiente => Izq.Coeficiente + Der.Coeficiente,
           Exponente => Izq.Exponente);

You can probably guess how this works just by looking at the
example. Technically it is a record aggregate, and you should
be able to find the detailed description in your Ada book. It
has the advantage of insisting that you remember to set all
fields. That does not really matter when there are only two
of them, but it can be a real advantage if there are many.

You can go a step further, just eliminate Aux
completely from your program, and write:

   return (Coefiente => Izq.Coeficiente + Der.Coeficiente,
           Exponente => Izq.Exponente);

OK, now finally back to the original issue.  You have an
error situation in this function, and the proper thing to do
is to raise an exception, but it is wrong to define this
exception INSIDE the function, why?  because the idea of an
exception is to let the CALLER decide what to do, and for
that the caller must be able to see the exception.

How to deal with this, well the function "+" must appear
inside a package, and that means the specification appears
in the package spec.  Here is an idea of how that should be
done:

function "+" (Izq, Der:  in Term) return Term;
-- This function takes two ....  and .....  and returns a
-- Term which ....  The exponents of Izq and Der must be
-- equal
--
-- Error conditions: raises Error_Suma if the exponents
-- are unequal.

I can't fill in the ....  since I don't know what this does
:-).  Just to remind you, the body now looks like:


  function "+" (Izq, Der: in Term) return Term is
  begin
    if Izq.Exponente = Der.Exponente then
      return (Coefiente => Izq.Coeficiente + Der.Coeficiente,
              Exponente => Izq.Exponente);
    else
      raise Error_Suma;
    end if;
  end "+";

Now, it is up to the caller to decide what to do about this
error.  For a simple program it may well be enough to do
nothing at all.  Now what happens if the error occurs, well
you have an unhandled exception and so the program
terminates with a nice message saying that the exception
Error_Suma was unhandled, and then you can if necessary go
into the debugger and find out why that happened.

Note how much nicer that is than the C style of returning an
error code which if you forget to check it, means that the
error is blithely ignored.  This has caused bugs in many
many C programs.  For example early versions of the Unix
editor just ignored a disk full condition, so you lost your
edited file with no warning that this had happened.

Or perhaps the CALLER will have an exception handler to
detect the error and take appropriate action.

One further point.  In some real large programs, there is a
protocol of logging errors, and that may mean it is
appropriate to modify your function as follows:

  function "+" (Izq, Der: in Term) return Term is
  begin
    if Izq.Exponente = Der.Exponente then
      return (Coefiente => Izq.Coeficiente + Der.Coeficiente,
              Exponente => Izq.Exponente);
    else
      raise Error_Suma;
    end if;

  exception
    when Error_Suma =>
      Error_Log ("error occured in "+" with args ....");
    raise;
  end "+";

Here the raise with no argument (often called a reraise),
reraises the same exception, so that the caller can deal
with it as appropriate.

Finally a quick note about the advice you received to
interface the C function exit.  This was non-Ada advice,
and shows the risk of getting advice from CLA, you can often
get correct advice which answers the wrong problem.

Interfacing exit answered the question of "how can I exactly
duplicate the style and content of my C program in Ada?"
But that's not what we are interested in doing here since
you are learning Ada :-)

Robert Dewar


Sent via Deja.com http://www.deja.com/
Before you buy.




  reply	other threads:[~2000-04-22  0:00 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2000-04-21  0:00 Exiting from a function or procedure Andres Tarallo
2000-04-21  0:00 ` Robert A Duff
2000-04-21  0:00 ` tmoran
2000-04-21  0:00   ` Andres Tarallo
2000-04-22  0:00     ` Robert Dewar [this message]
2000-04-22  0:00       ` Pablo Moisset
2000-04-23  0:00         ` Robert Dewar
2000-04-22  0:00       ` tmoran
2000-04-22  0:00         ` Ray Blaak
2000-04-22  0:00           ` David Starner
2000-04-23  0:00         ` Robert Dewar
2000-04-23  0:00           ` tmoran
2000-04-24  0:00             ` Robert Dewar
2000-04-24  0:00               ` tmoran
2000-04-24  0:00                 ` Robert Dewar
2000-04-24  0:00             ` Robert Dewar
2000-04-22  0:00       ` Ken Garlington
2000-04-24  0:00       ` Scott Ingram
2000-04-22  0:00   ` Robert Dewar
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox