[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference turris::languages

Title:Languages
Notice:Speaking In Tongues
Moderator:TLE::TOKLAS::FELDMAN
Created:Sat Jan 25 1986
Last Modified:Wed May 21 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:394
Total number of notes:2683

196.0. "A question of style?" by GENRAL::RINESMITH (GOD never says OOPS!) Wed Jul 20 1988 12:41

    What is the preferred method of calling external routines.
    
    As an example FMS allows the programmer to treat the routine as
    a subprogram and call it:
    
    			CALL	FDV$WAIT
    
    Or to treat it as a function.
    
    			cond_value = FDV$WAIT
    
    
    Perhaps this is nothing more than a question of style -- but I'd
    like to know what the preferred style is?
    
    	
T.RTitleUserPersonal
Name
DateLines
196.1Depends - is it in a product or not?CAIRN::HARRISThu Jul 21 1988 17:574
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.2Hang on a minuteLEROUF::PALOWatch out where those Huskies go...Wed Jul 27 1988 09:0214
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.3But if someone else wrote the routine...MOIRA::FAIMANA goblet, a goblet, yea, even a hoopThu Jul 28 1988 14:3925
    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.4A correction and two more approachesSKYLRK::LLOYDLloyd WheelerFri Jul 29 1988 10:1962
    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.5TOKLAS::FELDMANPDS, our next successSun Jul 31 1988 14:4536
    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.6my feelingsSAUTER::SAUTERJohn SauterTue Aug 02 1988 11:1710
    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.7don't write erroneous codeLEROUF::PALOWatch out where those Huskies go...Wed Aug 10 1988 08:3417
�    
�    	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.8TOKLAS::FELDMANPDS, our next successWed Aug 10 1988 13:0117
    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