Newsgroups: comp.edu,comp.lang.ada,comp.lang.c++,comp.lang.modula2,comp.lang.scheme
Path: cantaloupe.srv.cs.cmu.edu!europa.chnt.gtegsc.com!news.mathworks.com!news.kei.com!world!bobduff
From: bobduff@world.std.com (Robert A Duff)
Subject: Re: Comparison of languages for CS1 and CS2
Message-ID: <DBEwuo.8L@world.std.com>
Organization: The World Public Access UNIX, Brookline, MA
References: <3srsn5$q8d@galaxy.ucr.edu> <3tid5q$13a@bach.seattleu.edu> <3tje1h$t31@duke.cs.duke.edu> <3tkt5u$3vk@felix.seas.gwu.edu>
Date: Sat, 8 Jul 1995 19:30:24 GMT
Lines: 105
Xref: glinda.oz.cs.cmu.edu comp.edu:13121 comp.lang.ada:32302 comp.lang.c++:137332 comp.lang.modula2:11929 comp.lang.scheme:13031

In article <3tkt5u$3vk@felix.seas.gwu.edu>,
Michael Feldman <mfeldman@seas.gwu.edu> wrote:
>Interesting discussion. What I like about the Ada parameter rules is
>that the _semantics_ of a parameter (read-only vs. read-write) is
>de-coupled from the mechanism by which it is passed.

I beg to differ.

I think it is a flaw in the language design that different compilers can
behave differently in regard to by-copy vs. by-reference.  The
difference can be visible in the behavior of the program, and it is
possible to trip over these cases by accident, causing bugs and
non-portability.

I understand why the Ada rules are the way they are, and they do have
substantial benefits over those of Pascal and C.  Nonetheless, the fact
that Ada compilers can differ seems bad to me.  The RM says you
shouldn't write code that cares, but the compiler won't catch you --
that just doesn't cut it, IMHO -- Ada is supposed to help you out by
detecting accidental errors.

Furthermore, the exact rules about what's OK and what isn't are
extremely difficult to understand.  I remember a post from a couple of
months ago from some poor soul who didn't even realize that there are
cases where the program behaves differently depending on whether the
compiler chose by-copy or by-ref.

>All scalar parameters are passed by copy (and copy-back if OUT or
>IN OUT). This is required by the standard and is not necessarily 
>slower than doing it by reference. Indeed, if the parameter is read
>or written a number of times during the subprogram execution, it
>could be faster because lots of indirect references are avoided.

Yes, it is usually faster to pass small things by reference (in a
machine register, usually).

>Structured parameters (records, arrays) are permitted to be passed
>by copy or by reference. Most compilers pass them by reference,
>because here efficiency really is an issue if the parameters are of
>nontrivial size. Some Ada 83 compilers actually pass _small_ structured
>parameters by copy and large ones by reference.

Another case where pass-by-copy is typically used is for components or
slices of packed arrays and records:

    type Bit_Array is array(Integer range <>) of Boolean;
    pragma Pack(Bit_Array);
    procedure P(X: Bit_Array);
    ...
    X: Bit_Array(1..100_000);
    I: Integer := 17;
    J: Integer := 9_546;
    P(X(I..J)); -- usually passed by copy

P is expecting the address of a properly-aligned array, so X(I..J) will
be copied at the call site into a temp, and the address of that temp
passed.  Thus, the run-time semantics is pass-by-copy, even though P
thinks it's getting a reference.

The other alternative would be to pass a bit pointer to P.  But that
would penalize all callers, just because some caller might pass a slice.
Slices are fairly rare, and large slices of packed arrays are *very*
rare, so it makes sense to penalize that case.  Anyway, by saying Pack,
the programmer asked for small data space, knowing full well that it
might cost time -- that's what Pack means.

I suppose you could generate a different body for P if slices are
passed, but that requires the compiler to know about all the call sites,
which is difficult to manage given Ada's model of separate compilation.

Note that Pascal (from which Ada is descended) simply forbade these
cases -- the Pascal programmer has to make a copy by hand before passing
to a VAR parameter.

>The standard must allow parameters to be passed by reference to support
                                                    ^^^^^^^^^
>distributed systems

I think you mean "copy" above, in which case I agree.

>... in which the calling and called tasks could be
>in different address spaces.

Unlikely.  Ada's tasking model is strongly based on an assumption of
shared memory.  This is because there is no way for the compiler to
detect shared variables.  Note that the Ada 95 distribution model is
*not* based on distributing tasks, but on distributing packages and
partitions.  A remote procedure call will indeed use pass-by-copy
semantics.

>Here is the punch line, though - because an IN parameter _cannot_
>be modified within the subprogram (this can be easily checked by the
>compiler), the passing mechanism need be of NO concern to the
>casual or student programmer. IN means IN, OUT means OUT, and both
>are independent of "value" vs. "reference" jargon. This separation of
>concerns in parameter passing is one of the "little" things I really
>like in Ada. It's elegant.:-)

It would be elegant if it worked in all cases.  I disagree that the
casual programmer can ignore the issue.  It's not *that* hard to write
the problem cases by accident.  It doesn't happen every day, but it
happens often enough to be a problem, IMHO.  Ada is about making
programs work properly.

- Bob
