ken@rochester.UUCP (Ken Yap) (01/06/85)
The problem is not using constants in subroutine calls per se but changing a parameter that corresponds to a constant. BTW I saw a neat way of trapping this sort of error without any run-time overhead in the VMS Fortran compiler. Constants are placed in a read-only segment and the VM system traps any violation. True, you may get an obscure error message if your run-time doesn't understand what happened but it is better than carrying on innocently. Can anybody tell me if there are other compilers out there that also do this? If not, is there any reason this is not more widely practiced? (Other than lack of memory management hardware, that is.) -- Ken Yap UUCP: (..!{allegra, decvax, seismo}!rochester!ken) ARPA: ken@rochester.arpa USnail: Dept. of Comp. Sci., U. of Rochester, NY 14627. Voice: Ken!
dgary@ecsvax.UUCP (D Gary Grady) (01/07/85)
<> The FORTRAN code CALL FOO(A, 5, B) or some such calling a routine like this: SUBROUTINE FOO(X, Y, Z) .. Y = 1 .. RETURN END results in the constant 5 being changed to 1 in the rest of the program. The original poster had resorted to never using a constant in a subroutine call to get around this bug. But the fact is that it IS a compiler bug which existed in a number of early FORTRAN compilers but which I thought had long since been removed. An actual parameter (argument) in a CALL statement can be a variable, a subprogram name, a statement number (preceded by an asterisk), or an expression. A numerical constant is a degenerate case of an expression. All expressions should be dealt with by copying the result into a work area and passing a pointer to that. This has the nice side effect that a variable can be passed on a call-by-value basis simply by enclosing it in parentheses. I suspect the bad behavior of allowing constants to be altered by subroutine calls may stem from a cute trick in the compiler's lexical analyser. Constants can be inserted into the symbol table as self-defining "initialised variables." If this is done, statements such as 1 = 2 will work! This would no doubt bring much amusement to the denizens of net.math, but *I* am not amused. (That's ~:-) in standard notation.) Oh, well... -- D Gary Grady Duke University Computation Center, Durham, NC 27706 (919) 684-4146 USENET: {decvax,ihnp4,akgua,etc.}!mcnc!ecsvax!dgary
joe@petsd.UUCP (Joe Orost) (01/08/85)
In article <5143@rochester.UUCP> ken@rochester.UUCP (Ken Yap) writes: >The problem is not using constants in subroutine calls per se but >changing a parameter that corresponds to a constant. > >BTW I saw a neat way of trapping this sort of error without any >run-time overhead in the VMS Fortran compiler. Constants are placed in >a read-only segment and the VM system traps any violation. True, you >may get an obscure error message if your run-time doesn't understand >what happened but it is better than carrying on innocently. > >Can anybody tell me if there are other compilers out there that also do >this? If not, is there any reason this is not more widely practiced? >(Other than lack of memory management hardware, that is.) I don't know how they got away with that. Consider the following: CALL A(1.0) SUBROUTINE A(R) CALL B(R) END SUBROUTINE B(R) ... END Since scalar arguments are passed by value, the value 1.0 is copied into "R" on entry to subroutine A. On exit from A, the compiler can't know if B changed the value of R (it also doesn't know that the argument is a constant), so it must copy back the local copy of R into the constant 1.0. This prevents us from storing the constant in read-only memory. It seems that the only way thay can get away with storing passed constants in read-only memory is to CHECK what was passed on subroutine exit, and skip the update code if a constant was passed (yick!). According to the ANSI '77 Fortran standard 15.9.2 (15): "Actual arguments may be constants, symbolic names of constants, function references, expressions involving operators, and expressions enclosed in parenthesis IF AND ONLY IF THE ASSOCIATED DUMMY ARGUMENT IS A VARIABLE THAT IS NOT DEFINED DURING THE EXECUTION OF THE REFERENCED EXTERNAL PROCEDURE." This means that it is erroneous to pass a constant to a routine which changes its dummy argument. In our compiler, we allow a routine to change a dummy argument that is associated with an expression without side effects, but changing a constant or a symbolic constant is taboo. regards, joe -- Full-Name: Joseph M. Orost UUCP: ..!{decvax,ucbvax,ihnp4}!vax135!petsd!joe US Mail: MS 313; Perkin-Elmer; 106 Apple St; Tinton Falls, NJ 07724 Phone: (201) 870-5844 Location: 40 19'49" N / 74 04'37" W
davidg@dartvax.UUCP (David Gelhar) (01/08/85)
> BTW I saw a neat way of trapping this sort of error without any > run-time overhead in the VMS Fortran compiler. Constants are placed in > a read-only segment and the VM system traps any violation. The DTSS PL/1 compiler also knows how to keep constants in a read-only segment to allow them to be passed by reference. At the moment though, this is done only in a special compiler mode used for compiling the operating system; it is stylistically unpleasant to assign to a parameter that was passed a constant, but the language semantics allow it. For the operating system, the efficiency gained by passing write-protected constants by reference instead of making a copy was judged to be worth the price of altering normal PL/1 semantics a bit, but this is not done by default, lest novice users be baffled.
ech@spuxll.UUCP (Ned Horvath) (01/09/85)
This awful FORTRAN behavior is wired into the STANDARDS, to wit: FORTRAN uses call by 'value-result': each argument is copied, the copies are passed, and at return the copies are copied back to the original arguments. This is not quite the same as call by reference, since (for example) you can pass a variable which is in COMMON and the subroutine can modify either copy without the effects being replicated in the other -- until it returns! Unfortunately, many compiler writers simply implemented call by reference. You can test your compiler with the above example: pass a COMMON variable, modify the parameter, and see if the COMMON variable reflects the change WHILE STILL IN THE SUBROUTINE. If so, you have call by reference. Note that either call by reference or call by value-result will clobber your constants. The trick recently suggested -- pass (1.0) rather than 1.0 -- is a nice way to defeat this in FORTRAN, works fine in PL/I (call by reference) also. Beware, however: your 'optimizer' might just be braindamaged enough to strip off the parens! =Ned=
stew@harvard.ARPA (Stew Rubenstein) (01/10/85)
Joe Orost writes: > Consider the following: > > CALL A(1.0) > > SUBROUTINE A(R) > CALL B(R) > END > > SUBROUTINE B(R) > ... > END > > Since scalar arguments are passed by value, the value 1.0 is copied into "R" > on entry to subroutine A. On exit from A, the compiler can't know if B > changed the value of R (it also doesn't know that the argument is a > constant), so it must copy back the local copy of R into the constant 1.0. > This prevents us from storing the constant in read-only memory. It seems > that the only way thay can get away with storing passed constants in > read-only memory is to CHECK what was passed on subroutine exit, and skip the > update code if a constant was passed (yick!). In VMS Fortran, everything is passed by reference. Thus, in subroutine A, it doesn't copy 1.0 into "R", it copies the ADDRESS of the constant into the argument list to be passed to subroutine "B". No copying of the value is necessary. If subroutine "B" tries to alter the contents of this address, it will generate an access violation. Stew -- ----------------------- Stew Rubenstein UUCP: ihnp4!harvard!stew Harvard Chemistry ARPA: stew@harvard
jlg@lanl.ARPA (01/10/85)
> In VMS Fortran, everything is passed by reference. Thus, in subroutine A, > it doesn't copy 1.0 into "R", it copies the ADDRESS of the constant into > the argument list to be passed to subroutine "B". No copying of the value > is necessary. If subroutine "B" tries to alter the contents of this address, > it will generate an access violation. A lot of Fortran compilers do that. The CRAY compiler makes a copy of the constant and passes the address of the copy down to the subroutines. That way, if one of the subroutines changes the constant's value, only the copy is changed. The CRAY doesn't have 'read-only' memory locks, so it can't detect errors for this case (this may be the intended semanitcs anyway, see example below). SUBROUTINE A(R) !PRINT THE PRODUCT OF R AND (R+1), RETURN R+1 TEMP=R CALL SUCC(R) PRINT *,TEMP*R RETURN END SUBROUTINE SUCC(R) !RETURN SUCCESSOR OF R R=R+1 RETURN END Subroutine A will work correctly on the CRAY, even when its argument is a constant. The 'error' doesn't propagate back up to the calling routine, since only a copy of the constant was altered. (This is an admittedly contrived example, but it does demonstrate the point. I have used this technique to advantage before - it eliminates the need to use dummy variables to pass constant values to subroutines when I don't care about the returned value. I always carefully flag this trick as being non-standard.) The CRAY compiler is standard conforming too, since the standard doesn't require non-conforming code to be reported or corrected. The standard only requires that conforming programs be executed correctly. James Giles
dgary@ecsvax.UUCP (D Gary Grady) (01/11/85)
<> Warning: pathetic apology follows; overly sentimental readers may want to skip... WRONG!! I was WRONG!!!!! Mea culpa! I had claimed that existing FORTRAN compilers allow a constant to be passed as argument to a subprogram without that constant being damaged if it is modified within the subprogram. The FORTRAN compiler I used years ago behaved nicely in that regard. I have now discovered (by trying it out) that IBM's current VS FORTRAN compiler DOES allow you to make 1=2 and other horrors. I continue to consider that silly behavior. The runtime overhead of copying constants into a work area is trivial. But the fact remains that I was dead wrong, and wrong due for the simple reason that I fired off a response because I was "sure" of something before I tested it. In the future I will attempt to do better. I await suggestions for pennance. -- D Gary Grady Duke U Comp Center, Durham, NC 27706 (919) 684-3695 USENET: {seismo,decvax,ihnp4,akgua,etc.}!mcnc!ecsvax!dgary
jlg@lanl.ARPA (01/11/85)
> This awful FORTRAN behavior is wired into the STANDARDS, to wit: FORTRAN uses > call by 'value-result': each argument is copied, the copies are passed, and > at return the copies are copied back to the original arguments. This is not > quite the same as call by reference, since (for example) you can pass a > variable which is in COMMON and the subroutine can modify either copy without > the effects being replicated in the other -- until it returns! I just reread the standard, and that's NOT what it says. 'Value-result' is not required or implied by the standard (a standard conforming compiler is allowed to use 'value-result' if it remains semantically true to the standard's requirements). I've never worked with a Fortran compiler which used 'value-result' parameter passing (I have used several non-Fortran languages with this parameter passing method). According to the standard, you CAN'T pass a variable in both common and as a dummy argument (ANSI X3.9-1978 sec. 15.9.3.6). I don't know of any way for the compiler to check for violations of this constraint, but it is non- standard. > Unfortunately, many compiler writers simply implemented call by reference. > You can test your compiler with the above example: pass a COMMON variable, > modify the parameter, and see if the COMMON variable reflects the change > WHILE STILL IN THE SUBROUTINE. If so, you have call by reference. Most Fortrans use call by reference for ALL parameters. It's not unfortunate, it's just the way things are. I've never found it to be a hardship. > Note that either call by reference or call by value-result will clobber your > constants. The trick recently suggested -- pass (1.0) rather than 1.0 -- > is a nice way to defeat this in FORTRAN, works fine in PL/I (call by > reference) also. A good Fortran compiler will pass a copy of the constant, not the original in read-only memory. For example, The CRAY Fortran compiler makes a copy of all constant arguments into the temporary data area and passes these copies to the subroutine (the exception is that character constants are passed directly (I think - will have to check)). I think that the constraint against passing constants to subroutines which change argument values (ANSI X3.9-1978 sec. 15.9.2) should be removed. I like to pass constants to such routines when I don't care what the returned value is going to be, and the technique of passing copies allows this to work just fine. James Giles
donn@utah-gr.UUCP (Donn Seeley) (01/12/85)
From: ech@spuxll.UUCP (Ned Horvath) This awful FORTRAN behavior is wired into the STANDARDS, to wit: FORTRAN uses call by 'value-result': each argument is copied, the copies are passed, and at return the copies are copied back to the original arguments. This is not quite the same as call by reference, since (for example) you can pass a variable which is in COMMON and the subroutine can modify either copy without the effects being replicated in the other -- until it returns! ANSI X3.9-1978, section 15.9.3.6, p. 15-20: If a subprogram reference causes a dummy argument to become associated with an entity in a common block in the referenced subprogram or in a subprogram referenced by the referenced subprogram, neither the dummy argument nor the entity in the common block may become defined within the subprogram or within a subprogram referenced by the referenced subprogram. For example, if a subroutine contains the statements: SUBROUTINE XYZ (A) COMMON C and is referenced by a program unit that contains the statements: COMMON B CALL XYZ (B) then the dummy argument A becomes associated with the actual argument B, which is associated with C, which is in a common block. Neither A nor C may become defined during execution of the subroutine XYZ or by any procedures referenced by XYZ. As has been said before in this newsgroup, the standard does not require either call by reference or call by value-result -- it permits either. The equine mammal appears to have expired despite repeated concussions, Donn Seeley University of Utah CS Dept donn@utah-cs.arpa 40 46' 6"N 111 50' 34"W (801) 581-5668 decvax!utah-cs!donn
ndiamond@watdaisy.UUCP (Norman Diamond) (01/13/85)
> SUBROUTINE A(R) !PRINT THE PRODUCT OF R AND (R+1), RETURN R+1 > TEMP=R > CALL SUCC(R) > PRINT *,TEMP*R > RETURN > END > > SUBROUTINE SUCC(R) !RETURN SUCCESSOR OF R > R=R+1 > RETURN > END > > Subroutine A will work correctly on the CRAY, even when its argument is a > constant. The 'error' doesn't propagate back up to the calling routine, > since only a copy of the constant was altered. (This is an admittedly > contrived example, but it does demonstrate the point. I have used this > technique to advantage before - it eliminates the need to use dummy variables > to pass constant values to subroutines when I don't care about the returned > value. I always carefully flag this trick as being non-standard.) > > The CRAY compiler is standard conforming too, since the standard doesn't > require non-conforming code to be reported or corrected. The standard only > requires that conforming programs be executed correctly. > > > James Giles Yes, the CRAY compiler conforms to the standard. Your program does not conform to the standard. A compiler can do whatever it wishes in cases that do not have to be reported or corrected. A compiler can implement dozens of extensions, and technically just be required to report when the extensions are used. A program that uses such extensions is a non-conforming program, and no one should compilain when it doesn't port very easily. About subroutine A working "correctly", Mr. Giles meant that subrouting A does what he wants it to do. Lots of other possibilities would also be correct, as far as the standard is concerned. -- Norman Diamond UUCP: {decvax|utzoo|ihnp4|allegra|clyde}!watmath!watdaisy!ndiamond CSNET: ndiamond%watdaisy@waterloo.csnet ARPA: ndiamond%watdaisy%waterloo.csnet@csnet-relay.arpa "Opinions are those of the keyboard, and do not reflect on me or higher-ups."