From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,6a0391eb7e0327d5 X-Google-Attributes: gid103376,public X-Google-ArrivalTime: 2003-02-08 23:13:29 PST Path: archiver1.google.com!news1.google.com!sn-xit-02!sn-xit-03!sn-xit-01!sn-xit-08!supernews.com!nntp2.aus1.giganews.com!nntp.giganews.com!newsfeed1.earthlink.net!newsfeed2.earthlink.net!newsfeed.earthlink.net!wn11feed!wn13feed!wn12feed!worldnet.att.net!204.127.198.203!attbi_feed3!attbi.com!rwcrnsc53.POSTED!not-for-mail Message-ID: <3E45FFCB.90109@attbi.com> From: "Robert I. Eachus" User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.0.2) Gecko/20021120 Netscape/7.01 X-Accept-Language: en-us, en MIME-Version: 1.0 Newsgroups: comp.lang.ada Subject: Re: Ada style of passing 'in' parameters considered dangerous? References: <86isvuzabx.fsf@hoastest1-8c.hoasnet.inet.fi> Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit NNTP-Posting-Host: 24.62.164.137 X-Complaints-To: abuse@attbi.com X-Trace: rwcrnsc53 1044774806 24.62.164.137 (Sun, 09 Feb 2003 07:13:26 GMT) NNTP-Posting-Date: Sun, 09 Feb 2003 07:13:26 GMT Organization: AT&T Broadband Date: Sun, 09 Feb 2003 07:13:26 GMT Xref: archiver1.google.com comp.lang.ada:33932 Date: 2003-02-09T07:13:26+00:00 List-Id: Robert A Duff wrote: > The problem with this Ada rule is that it violates abstraction. > You don't know whose responsibility it is to worry about aliases > -- the caller or callee. The callee. The abstraction rules in Ada basically mean that the callee has to support all possible callers, including those that don't exist yet. In addition, there is the assumption that anything that the user of a package needs can be found in the package specification. (Of course, many people including myself are quite willing to use comments in the specification to document assumptions made by the body, exceptions that may be raised, etc.) > How about this example: > > We have a record representing fractions of whole numbers: > > type Fraction is > record > Numerator: Integer; > Denominator: Positive; > end record; > > procedure Reciprocal(Result: out Fraction; X: Fraction); > -- Sets Result to the reciprocal of X. > > procedure Reciprocal(Result: out Fraction; X: Fraction) is > begin > if X.Numerator > 0 then > Result.Numerator := X.Denominator; > Result.Denominator := X.Numerator; > ... etc > > It seems reasonable (without seeing the body of Reciprocal) to do: > > Reciprocal(Foo, Foo); > > If Fractions are passed by copy (which is probably most efficient, since > they fit in just two registers), then it works fine. If they're passed > by reference, we get the wrong answer. ...and if you write the body as: procedure Reciprocal(Result: out Fraction; X: Fraction) is begin if X.Numerator > 0 then Result := (X.Denominator, X.Numerator); ... etc There is no problem. (The aggregate must be completely evaluated before it can be assigned.) Of course it makes more sense to implement this as a function: function Reciprocal(X: Fraction) return Fraction is begin if X.Numerator > 0 then return (X.Denominator, X.Numerator); ... etc If the subprogram is inlined, then calls of the form Reciprocal(Foo, Foo); or Foo := Reciprocal(Foo); may require more instructions than Reciprocal(Foo, Bar) or Bar := Reciprocal(Foo); But this is not a problem, it is exactly what you want--the most efficient code in either case. So in general, the problem of aliasing exists in all high level languages, and different language take different approaches to defining what happens in the painful, sometimes not even possible to recognize even at execution time, cases. However, in well written Ada there are very few cases where the issue is likely to come up. This is because Ada provides lots of ways for a subprogram or body to be written in a way that makes its correctness independent of aliasing and parameter passing conventions. But the most important thing to remember is that in Ada the place to solve the (potential) problem is in the body of the callee, not in the caller or the specification of the callee. For example, if you have a record parameter and must force copy semantics, simply write: procedure Reciprocal(Result: out Fraction; X: Fraction) is Temp := X; begin... If the compiler passes X by copy, any decent optimizer will eliminate the "second" copy. If you later change the code as (way) above and don't need to force copy semantics, you only have to change the body--which you are doing anyway--and not the specification (forcing recompiles) or all of the callers.