T.R | Title | User | Personal Name | Date | Lines |
---|
196.1 | Depends - is it in a product or not? | CAIRN::HARRIS | | Thu Jul 21 1988 17:57 | 4 |
| If anything can possibly go wrong, the preferred method is to use the "function"
method and check the status for errors. The subroutine method should not be
used for product code that needs to be robust.
-Kevin
|
196.2 | Hang on a minute | LEROUF::PALO | Watch out where those Huskies go... | Wed Jul 27 1988 09:02 | 14 |
|
re: .-1
This simply is not true. The subprogram needs to take a decision whether
its condition values are always returned (good and bad) or whether the
bad ones are signalled. Both are correct depending on their environment
of usage ( and there are proponents for both cases ). A good example is
the STR$ procedures which typically signal error conditions and LIB$
procedures which generally return them.
Please refer to Volume 8a Chapter 2 (VAX Procedure Calling and Condition
Handling Standard) for more information.
\rikki
|
196.3 | But if someone else wrote the routine... | MOIRA::FAIMAN | A goblet, a goblet, yea, even a hoop | Thu Jul 28 1988 14:39 | 25 |
| My interpretation is that the author of .0 is not asking how
to *write* external subroutines, but how to *call* an existing
routine which returns a condition code. In that case, as Alan
says, you want to test the return value unless you absolutely
know that it cannot fail.
Unless you know what to do with a failure status when you get
it, the following is probably adequate:
STATUS = FDV$WAIT(...);
IF "STATUS is not odd" THEN
CALL LIB$SIGNAL [or LIB$STOP] (STATUS, 0);
When coding in Pascal, I will sometimes define a routine like
procedure CALL_AND_TEST ( STATUS : integer );
begin
LIB$SIGNAL(STATUS, 0);
end;
and then I can just code CALL_AND_TEST( FDV$WAIT(...) ). Of
course, this is even better in BLISS where you can use a macro.
-Neil
|
196.4 | A correction and two more approaches | SKYLRK::LLOYD | Lloyd Wheeler | Fri Jul 29 1988 10:19 | 62 |
| Re .3:
I believe that you left out the TEST in "CALL_AND_TEST". In addition,
at least in this case you need not mourn the absence of macros in VAX
Pascal (or Ada); you can create "inlined procedures" (under many
circumstances, the compiler will even inline them for you without your
suggestion). I believe that the Pascal syntax is (assuming that
LIB$SIGNAL is visible):
[ OPTIMIZE (INLINE) ]
procedure CALL_AND_TEST ( STATUS : integer );
begin
if NOT ODD (STATUS) then
begin
LIB$SIGNAL (STATUS)
end
end;
Of course, if you really want this inlined, you currently need to
%INCLUDE this source text in all modules using the routine (you
currently can't inline between separate compilation units in VAX
Pascal).
Re .0:
In addition, some facilities allow the *caller* to specify the
mechanism used to indicate error conditions. For example, you can
set "System Service Exception Mode" ($SETSFM) if you want system
services to signal exceptions rather than return failure status,
although this *will* affect system service calls by *any* code in
the process until the previous mode is restored (sort of a nasty side
effect). This global effect makes $SETSFM very difficult to use
unless you can guarantee that all asynchronously invoked routines
and all routines invoked as a consequence of your code either tolerate
both exceptions and status returns or perform $SETSFM calls to save,
modify, and later restore the mode appropriately.
[I've never encountered someone using $SETSFM; I doubt that it
has been used in *all* DIGITAL and third-party "callable" software
packages (eg, FMS, TDMS, DATATRIEVE, Rdb, DBMS, EVE, EDT, RealTime
Calling Standard, et cetera).]
Alternatively, the VAXELN kernel allows you to choose on a per-call
basis by "breaking" with the Procedure Calling and Condition Handling
standard; instead of using R0 (actually, perhaps in addition to using
R0, in which case VAXELN still adheres to the standard), status is
returned via an optional parameter (all services are *procedures* not
*functions*). The called routine understands optional parameters, and
if the status parameter is not supplied, the routine signals errors
instead of returning a status. This avoids the "side effect" problem
of $SETSFM. Alternatively, you could pass a "control flag" into the
routine which indicates how you'd like your errors.
Unless FMS has a routine which can set "FMS Failure Exception Mode",
you have no choice: you must check the return status. I also suspect
that you need to alter your processing based upon the status code
returned (to cope with different errors differently), so you cannot
even take advantage of the "if it is an error, signal it" approach.
If your language is picky about "case" statements, LIB$MATCH_COND
may help make your job easier.
Lloyd
|
196.5 | | TOKLAS::FELDMAN | PDS, our next success | Sun Jul 31 1988 14:45 | 36 |
| I wonder. How do people feel about routines that are documented
as always returning SS$_NORMAL. For example, consider the following:
status =
str$concat (
fixed_result_string,
dynamic_source_string_1,
dynamic_source_string_2);
if .status EQL SS$_TRU then �report a truncation error�;
str$free1_dx (dynamic_source_string_1);
status = str$free1_dx (dynamic_source_string_2);
STR$FREE1_DX is documented as always returning SS$_NORMAL. Do you
believe
a) You should always throw away the value of STR$FREE1_DX, as in
the first call to it above.
b) You should store the value of STR$FREE1_DX, as in the second
call to it above, but you needn't ever examine the result
or
c) You should always test the value of STR$FREE1_DX, even though
it should always be SS$_NORMAL?
Here's the extra credit question:
Suppose it is obvious from the code and context that STR$CONCAT can't
return SS$_TRU in a particular situation. This might be true if
the code explicitly tests the lengths of the various parameters,
or it might be because you use a dynamic destination instead of
a fixed-length destination. Is it still necessary to test the result
of STR$CONCAT?
Gary
|
196.6 | my feelings | SAUTER::SAUTER | John Sauter | Tue Aug 02 1988 11:17 | 10 |
| I prefer to always test the result of a call, even if it is documented
as always returning SS$_NORMAL. If the result is false, I signal
a fatal internal error. This defends my code from changes in the
specifications of routines that I call, perhaps years after I have
left the project.
By the way, it is possible to STR$CONCAT to return a truncation
error even if the result is a dynamic string: dynamic strings are
limited to 65535 bytes.
John Sauter
|
196.7 | don't write erroneous code | LEROUF::PALO | Watch out where those Huskies go... | Wed Aug 10 1988 08:34 | 17 |
|
�
� status =
� str$concat (
� fixed_result_string,
� dynamic_source_string_1,
� dynamic_source_string_2);
� if .status EQL SS$_TRU then �report a truncation error�;
� str$free1_dx (dynamic_source_string_1);
� status = str$free1_dx (dynamic_source_string_2);
�
Gary, you should know better than *not* to use LIB$MATCH_COND when
comparing condition values. Otherwise there is a bit more work to do it.
\rikki -- mission : enforce adherence to VAX CONDITION HANDLING standard
|
196.8 | | TOKLAS::FELDMAN | PDS, our next success | Wed Aug 10 1988 13:01 | 17 |
| Boy, try to write a simple fragment, for illustrative purposes only,
and everyone has to find a bug. No wonder we don't put enough examples
into our documentation :-).
With respect to STR$CONCAT and truncation errors, perhaps the
documentation needs to be clarified. The VMS V4.4 documentation for
truncation errors by STR$CONCAT says "One or more characters were not
copied into the destination string. This can happen when the
destination is a fixed-length string." This shows the importance
of complete, precise writing, to avoid misleading the casual reader
(me). I wonder if I'm the only one who made the erroneous inference.
And yes, LIB$MATCH_COND should be used. I know people who've been
burned by this when calling layered products, but even with system
services and RTL routines, it's usually better to be safe than sorry.
Gary
|