Version 1.6 of ais/ai-00304.txt

Unformatted version of ais/ai-00304.txt version 1.6
Other versions for file ais/ai-00304.txt

!standard 12.5(8)          03-09-30 AI95-00304/01
!standard A.4.4
!standard 3.2.1(3)
!class amendment 02-07-11
!status No Action (8-0-0) 04-03-07
!status work item 03-09-30
!status received 02-07-11
!priority Low
!difficulty Hard
!subject Reemergence of "=" in generics.
!summary
A new category of types is proposed called "aliased" types. Aliased types are like tagged types in the following ways:
1) They are always passed by reference; 2) Formal parameters allow 'Access and 'Unchecked_Access; 3) User-defined "=" overrides the predefined "="
completely, including in a generic and in equality of enclosing objects;
4) Formal derived types use the actual's primitives
rather than the ancestor's primitives;
5) Subtype conformance is required when overriding
an inherited or predefined primitive subprogram, as opposed to just type conformance.
The reserved word "aliased" may be used after "is" in a private type declaration, a formal private type declaration, and a composite type declaration. If a partial view is aliased, then the full view must be aliased. All tagged types are implicitly aliased types.
Individual stand-alone objects must still be explicitly marked "aliased" if 'Access is to be used with them.
!problem
There is a requirement that language-defined private types have "composable" equality, that is, if a type defined in a language-defined package is used as a component of another type, then equality on the enclosing type "works right." The most relevant example is bounded strings, where equality is defined in terms of the characters of the abstract string represented, as opposed to the underlying representation, which may have additional padding characters which should not participate in the comparison.
Tagged types "work right" in this context, where a user-defined equality operator is used in place of the predefined equality operator everywhere, including in generic instances and in equality for enclosing objects. What is desired is a way to have the same "correct" semantics for user-defined equality, but without making the type into a tagged type, which has potentially undesired implications (e.g. no defaults for discriminants, type descriptors, implicitly generated stream attribute functions, support for Internal_Tag, etc.).
Once equality operators "work right" in generics, it would be natural to want other user-defined primitives to work right for formal derived types (that is, the actual's rather than the ancestor's primitives are used in the instance).
Finally, there is a generally unrelated need on occasion to ensure that a type is always passed by reference, and that 'Access or 'Unchecked_Access can be used meaningfully on formal parameters of the type. Tagged types also have this characteristic, and hence there might be some value in supporting these two desires with a single solution.
!proposal
See summary.
!wording
TBD.
!example
Here is the bounded strings example:
package Ada.Strings.Bounded is generic Max : Positive; package Generic_Bounded_Length is ... type Bounded_String is private; ... private function "="(Left, Right : Bounded_String) return Boolean; type Bounded_String is aliased record -- "aliased" ensures no reemergence of predefined "=" Length : Natural range 0..Max := 0; Data : String(1..Max); end record; ...
By using "aliased" we ensure that the user-defined "=" which presumably only compares BStr.Data(1..BStr.Length) will be used in all cases. Without this, either the bounded string will have to be a tagged type, or Data will have to be default-initialized to all zeros, something which could add substantially to the cost of using the type if Max is relatively large.
---------
Here is an example of a type that is used to provide top-down "context" while processing a tree representation of a program or other modular construct. There happens to be a user-defined "=" operator, and a need for the type to be passed by reference, with 'Access allowed on parameters.
I'll admit this is a bit of a farfetched example, but I have certainly encountered something similar to this in real static analysis programs.
package Contexts is
type Context is aliased private; -- full type must be aliased type Context_Ptr is access all Context;
procedure Initialize_New_Context(Ctx : in out Context; Current_Unit : Unit_Type; Is_Read_Only : Boolean := False; Enclosing_Context : Context_Ptr := null);
function "="(Left, Right : Context) return Boolean; -- compares Current_Unit and Is_Read_Only; ignores Enclosing_Context pointer
function Is_Read_Only(Ctx : Context) return Boolean; function Current_Unit(Ctx : Context) return Unit_Type; function Enclosing_Context(Ctx : Context) return Context_Ptr;
private
type Context is aliased record Enclosing_Context : Context_Ptr; Current_Unit : Unit_Type; Is_Read_Only : Boolean; end record;
end Contexts;
with Contexts; use Contexts; package body Analyzer is procedure Process_Unit(Unit : Unit_Type; Cur_Context : in out Context) is Local_Context : Context; begin Initialize_New_Context(Local_Context, Current_Unit => Unit, Enclosing_Context => Cur_Context'Unchecked_Access); ... Process_Innards(Unit, Cur_Context => Local_Context); ... end Process_Unit; ...
!discussion
We considered just making all record types "work right" but there were felt to be too many possibilities for subtle incompatibilities.
One interesting side-effect of having a category of formal private types that is always passed by reference, and cannot be matched by an elementary type, is that a particularly simple form of generic sharing would be enabled by it. If the formal types of a generic were all aliased private, then pointers could be used for everything, and the code could relatively easily be constructed to be sharable.
!ACATS Test
ACATS tests are needed for these features.
!appendix

From: Tucker Taft
Sent: Thursday, June 13, 2002  8:31 PM

Robert A Duff wrote:

> Randy said:
>
> > Deleting bounded strings would make more sense. :-)
>

...

> But the implementation of Bounded_Strings initialized all 1000
> characters (because some AI says "=" has to compose on these things)!

It might be time to address this issue directly, namely that "=" reemerges in
generics, and doesn't compose.  We have special rules for the "=" operator for
tagged types, why not make this operator special for all types, requiring that
if user-defined using the base subtype for scalar formals, or the first subtype
for other types, then the predefined one does *not* reemerge in generics, and
it composes properly.

Yes, I realize this would not be upward compatible, and would not be
the same as other operators (but those don't *need* to compose), but
remember that until Ada 95, it was very difficult to define your own equality
operator anyway on a non-limited type.

At the very least, we should do this for record and private types.  And of
course, once you do it for private types, things get weird if you don't
do it for all types.

****************************************************************

From: Tucker Taft
Sent: Thursday, June 13, 2002  9:25 PM

Anticipating the "shared generics" implementation problems,
I humbly recast this as a proposal to make user-defined "="
compose properly and hide the predefined "=" in generics
only for record types (and for private types that are record
types "deep down").

****************************************************************

From: Randy Brukardt
Sent: Thursday, June 13, 2002 10:27 PM

> Anticipating the "shared generics" implementation problems,

Nice to hear that some people are responding to the training. :-)

> I humbly recast this as a proposal to make user-defined "="
> compose properly and hide the predefined "=" in generics
> only for record types (and for private types that are record
> types "deep down").

From a shared generics perspective, it would make more sense to simply have
this happen for generic formal private types (and maybe generic formal
derived record types?). After all, we'd need to use a thunk for any generic
formal private "=", so why shouldn't all types work right in that context.
Redefinition of "=" on elementary types is a lot rarer, and both the
compatibility issues and the runtime cost wouldn't be worth it.

But my gut feeling is that this is too incompatible to consider. People have
been working around this problem since time immemorial (i.e. 1983), and we'd
have to make sure that all of the workarounds still worked.

****************************************************************

From: Pascal Leroy
Sent: Saturday, June 15, 2002  4:46 AM

> Yes, I realize this would not be upward compatible, and would not be
> the same as other operators (but those don't *need* to compose), but
> remember that until Ada 95, it was very difficult to define your own
> equality operator anyway on a non-limited type.

Well, Ada 95 has been around for 7 years, and the Ada 83 trick was well
publicized at the time, so I think that we cannot afford the
incompatibility.

On the other hand, if we had a mechanism to specify, on the declaration of
"=", that it has to compose and doesn't reemerge, that would be both
compatible and useful.  It could be done by some sort of
pragma/attribute/new syntax/whatever.

****************************************************************

From: Bob Duff
Sent: Saturday, June 15, 2002  7:24 AM

As a pragma, it violates Bob Duff's Rule of Good Taste in Pragmas,
which is, "Pragmas should not have a strong effect on high-level
semantics."

As new syntax, it's ugly, because you always want it.

But I admit that one of these is probably the best solution,
given the (rather subtle) upward compatibility concern.

****************************************************************

From: Pascal Obry
Sent: Saturday, June 15, 2002  7:24 AM

Right, but would be quite cleaner than introducing a pragma. In such
a case the compiler could certainly warn and point out where the
compatibility problems are, no ?

****************************************************************

From: Bob Duff
Sent: Sunday, June 16, 2002 12:17 PM

> Right, but would be quite cleaner than introducing a pragma.

Sorry, I don't understand what you mean.

>... In such
> a case the compiler could certainly warn and point out where the
> compatibility problems are, no ?

Yes, a compiler could warn if you pass a type with user-defined "=" to a
generic, and call "=" in the generic.  Also if you declare a record or
array component with user-defined "=", and call "=" on the outer thing.

In fact, such a warning might be useful even if the language is *not*
changed.

****************************************************************

From: Tucker Taft
Sent: Sunday, June 16, 2002 12:17 PM

> Sorry, I don't understand what you mean.

I meant that I think it would be better to "fix" the language by introducing
an slight incompatibility (the compiler will issue a nice warning to help
the migration) than to have a new pragma that change the semantic.

> In fact, such a warning might be useful even if the language is *not*
> changed.

Agreed.

****************************************************************

From: Robert Dewar
Sent: Sunday, June 22, 2002 11:12 AM

I am *completely* opposed to ANY deliberate incompatible changes at this stage.
None of the "improvements" to Ada being discussed is remotely worth the effort
of dealing with having to make changes in large legacy programs as a result
of gratuitous incompatibilities.

If we could not successfully argue for this incompatible change for Ada 9X, it
is sheer folly to consider sneaking it in for the next version of Ada.

Speaking for ACT, if any updated version of Ada has incompatibities of this
nature it would be sufficient for us to simply ignore the new feature. We
cannot afford to affect existing customers in this manner.

The idea that when you recompile millions of lines of legacy code that a
warning will be sufficient help to safely change code with minimal effort
is bogus!

****************************************************************

From: Tucker Taft
Sent: Tuesday, September 30, 2003 10:22 AM

In the past few weeks, there has been some
discussion of the pain associated with reemergence
of "=" when trying to create (untagged) private types whose
equality "composes" properly.  The problem is that
the predefined "=" compares all components, which
is painful for things like bounded strings, where
parts are potentially uninitialized.

One possibility is to change the rules for (untagged)
composite types so they match the rules for tagged types, and
say that a user-defined "=" overrides completely
the predefined "=", preventing it from reemerging
in generics or in the equality for enclosing types.
Unfortunately, this could have subtle incompatibilities
(though I tend to believe it would fix many more
subtle bugs than it would cause).

In any case, this leads to a desire to "mark" the
type or the "=" operator in some way to say that
it *really* overrides the predefined operator, now
and forever.

One possibility is to have a kind of type that
"works right" as do tagged types, but not have
the overhead of a tag or the possibility of type
extension.

In the mean time, there has been some talk about
having types that are always passed by reference,
and for which 'Access is defined for formal parameters,
which again matches the semantics of tagged types.

The natural suggestion for this latter situation is
to allow "aliased" to be used on type declarations,
roughly in the same syntactic location as the word
"tagged" is used, namely right after the "is" and
before "record", "private", or "limited" (and perhaps
also before "array".  E.g.:

    type T is aliased record
        ...
    end record;

Parameters of type T would always be passed by reference,
and the 'Access attribute would be permitted on formal
parameters of type T, and 'Address would always be meaningful.
All tagged types are implicitly "aliased," so an "aliased"
private type could be completed with a tagged full type.  Note
that stand-alone objects would still need "aliased" if 'Access
is to be applied to them, as is true now for "tagged."

Note also that aliased private types could *not* be completed
by elementary types (since they are passed by copy).
That could be interesting, as it might enable a poor-man's
generic sharing, if the formal types are all aliased private,
the implementation can safely use pointers and pass by
reference everywhere in the shared code body.

Perhaps we can kill two birds with one stone here.
Perhaps we can say that this new kind of type ("aliased",
or perhaps some other term), not only has by-reference
parameter passing and aliased formals, but also has
rules for overriding of primitives that requires subtype
conformance (as required for tagged), thereby allowing
generics to always use the user-defined primitive of
the actual type, rather than having the predefined operator,
or ancestor primitive, reemerge in generics (and enclosing
equality ops).

Bob Duff and I used to say that "tagged types work right" when
it comes to generics.  We could generalize this to say
"aliased types work right."  That is, a user-defined "="
for an aliased type would hide the predefined "=" now
and forever.  Also, for a formal derived aliased type, the
actual's primitive operations rather than the ancestor's
primitives would be used in the generic instance.  Finally,
when overriding a primitive of an aliased type, the parameter
profile of the overriding must be subtype conformant, not just
type conformant.

Note that presuming we define all tagged types to be
implicitly "aliased" types, then the number of rules
in the manual can stay about the same, its just some of them are phrased
in terms of "aliased" and "non-aliased" types rather than
"tagged" and "untagged" types.

Any comments?

****************************************************************

From: Randy Brukardt
Sent: Tuesday, September 30, 2003  5:22 PM

This is AI-00304, assigned to one Tucker Taft. Please feel free to do your
homework. :-)

My first reaction is that the idea is OK, but seems like killing a gnat (er,
fly) with a cannon. Detailed reactions will have to wait until after the
meeting.

****************************************************************

From: Tucker Taft
Sent: Tuesday, September 30, 2003  8:16 PM

Oh, thanks for the pointer.  Here is a quick draft of AI-304.

[This is version /01 of the AI.]

****************************************************************

From: Randy Brukardt
Sent: Tuesday, September 30, 2003  8:32 PM

> One interesting side-effect of having a category of formal
> private types that is always passed by reference, and cannot
> be matched by an elementary type, is that a particularly
> simple form of generic sharing would be enabled by it.
> If the formal types of a generic were all aliased private,
> then pointers could be used for everything, and the code
> could relatively easily be constructed to be sharable.

Which of course is how Janus/Ada works for private types. If the actual type is
pass-by-copy, we 'fake' pass by copy at the call site.

****************************************************************

From: Robert I. Eachus
Sent: Friday, February 13, 2004  6:30 PM

I thought there was an Ammendment AI fixing the problems with aliased
(and 'Access and 'Unchecked_Access).  I just looked through the Ada
Issues database and didn't find one.  Did it get filed under a name
without aliased in the title, or is my memory playing tricks on me?
(And if so, should I send this to Ada Comment?)

To elaborate on the problem.  It makes no sense for an object of a type
with aliased components to be other than aliased.  But currently that is
not the case.  It either results in having to write aliased all over the
place, or the kludge of using an access to the first component of the
array or record when you really mean the object as a whole.  (And yes,
there may be cases where the two are not the same, which is what makes
it a kludge.)

I would rather allow types (and subtypes) to be declared as aliased.
That requires a syntax change, but it is certainly much clearer.  Just
stating that objects with aliased components are implicitly aliased
fixes the painful part.  (And as far as I  can tell, should just be a
change in the semantics part.  I can't imagine any compiler currently
creates unaliasable records or arrays with aliased components. ;-)

****************************************************************

From: Tucker Taft
Sent: Friday, February 13, 2004  8:04 PM

I made some suggestions about allowing the word "aliased"
pretty much anywhere the word "tagged" is allowed.
I think it is a good idea for various reasons.
Bob and I used to say that "tagged types work right"
(e.g. predefined equality doesn't reemerge in generics,
formal derived tagged types get the "right" primitives,
etc.).  With this change, we could say "aliased" types
work right.  They would sort of be like tagged records
without the tag.  The actual wording changes in the
manual didn't seem that bad.  Essentially some of
the rules that currently say "tagged" would say aliased.
And of course any tagged type is implicitly also
an aliased type.  Presumably all task and protected
types would be aliased as well.

But alas, I never took it far enough to produce an AI.
Maybe if someone prods me, I will find the time.

****************************************************************

From: Tucker Taft
Sent: Friday, February 13, 2004  8:57 PM

I was wrong -- it did make it into an AI:
AI-304, "reemergence of "=" in generics"

****************************************************************

From: Robert I. Eachus
Sent: Friday, February 13, 2004  9:48 PM

Thanks, I thought I remembered reading it.  Now let me make a few
suggestions....

First, the name of the AI should be changed to Aliased types and
reemergence of "=", or the other way around. ;-)

Second, I think that a lot of noise arose due to something that was (I
hope) not a serious suggestion. I think for this proposal to be
accepted, it must be totally upward compatible.  Which means that any
new rules have to apply to the new types only.  To be honest: Tucker's
proposal is to make aliased types like tagged types in generics.  I
actually think that this is not just a good idea, I think it is the only
way to meet the upward compatibility goal. I can imagine cases where the
compiler can't tell that an aliased type has a full declaration that is
tagged. (We could disallow that.)  But more important is the generic
formal matching issue.

For most compilers treating the (semantically) new category of types as
tagged types with no visible primitive operations, or "=" as the only
such operation, should be relatively painless.  But as I see it the big
fix would be to fix the current problem of records and arrays with
aliased components not being aliased.  I would prefer that the "fix" be
that such types are implicitly aliased, but putting aliased in the type
declaration would be no big deal.

I also think that in that case (explicit declaration required for types
with aliased components to also be aliased) it is worth allowing the
aliased keyword in subtype declarations.  But there is no free lunch.
If you have aliased subtypes, you have the possibility of calling a
subprogram that has a parameter declared to be of an aliased subtype
with a value of the type but not the subtype.  Dectecting the problem
and rasing an exception is one solution.  But it seems a shame to create
the same snake pit all over again in a much smaller area.   Better I
think is to use Randy's approach.  Say that subtype conversion to an
aliased subtype may cause copying and leave it at that.  (In other words
it may result in a value in a register being put on the stack so it can
be passed by reference.)  In any case, that will have to be done with
explict type conversions.

We require or dissallow aliased in derived type declarations depending
on the parent view.  I don't think that simplifies anything since we
currently allow derivation from private types where the full view is
tagged.  This would just be another instance of the same.  And the
thought of needing or not allowing aliased depending on the full type
both raises upward compatibility issues and contract model violations.

I think the way to go is that a formal of an aliased type can be matched
only by any aliased type or any tagged type. An aliased type can match
any private or limited private formal type. That way, if you want to use
'Access in a generic on an object of a genric formal type, either the
object or the formal type has to be explicitly aliased.

****************************************************************

From: Tucker Taft
Sent: Saturday, February 14, 2004  3:29 PM

> ...  I think for this proposal to be
> accepted, it must be totally upward compatible.

I believe it is upward compatible as written/

****************************************************************

From: Robert I. Eachus
Sent: Saturday, February 14, 2004  7:46 PM

I agree.  But someone looking at the comments might think otherwise.  In
one comment you (Tucker) said: "It might be time to address this issue
directly, namely that "=" reemerges in generics, and doesn't compose. We
have special rules for the "=" operator for tagged types, why not make
this operator special for all types, requiring that if user-defined
using the base subtype for scalar formals, or the first subtype for
other types, then the predefined one does *not* reemerge in generics,
and it composes properly.

"Yes, I realize this would not be upward compatible, and would not be
the same as other operators (but those don't *need* to compose), but
remember that until Ada 95, it was very difficult to define your own
equality operator anyway on a non-limited type."

This is not part of the proposal as written, and it seems to have met
with some pretty negative reaction. I think some people may have thought
this was part of the proposal. Certainly the aliased types they can
compose like tagged types, since right now the only aliased types are
tagged types. If someone does want to put a proposal for composition of
equality in untagged types that is
upwardly compatible on the table fine. (I am happy with the current
situation where "=" can be passed as a formal subprogram parameter with
a default. It makes it a non-issue as far as I am concerned.)

****************************************************************

From: Robert I. Eachus
Sent: Saturday, February 14, 2004  9:13 AM

I'm glad I brought it up then.  As I said in my previous post, I think
that if we really want to get aliased (and 'Access) right, there has to
be some way for a user to declare a TYPE to be aliased.  Subtype would
be nice, but type is important.  The problem is that right now, if an
abstraction author wants to use access types internally, he can either
declare a type that has aliased components and write lots of wrapper
suprograms, or make the user declare all objects as aliased, and all the
operations on the type must have access parameters.  I personally think
the latter is too ugly to use, and the former means that I have a "real"
type which is passed by access, and a wrapper type which the user sees.

But in the case of arrays, that gets painful too:

  M,N: Integer := 10;

  type Accessable_Matrix is array (Integer range 1..M, Integer range
1..N) of Long_Float;

  type Matrix is record
    Actual: aliased Accessable_Matrix;
  end record;

  procedure Plus (L,R, Result: access Accessable_Matrix) is
  begin
    for I in L'Range(1) loop
      for J in L'Range(2) loop
        L(I,J) := R(I,J);
      end loop;
    end loop;
  end Plus;

  function "+" (L,R: Matrix) return Matrix is
    L_Kludge: Matrix;
    pragma Import(Ada,L_Kludge);
    for L_Kludge'Address use L'Address;
    R_Kludge: Matrix;
    pragma Import(Ada,R_Kludge);
    for R_Kludge'Address use R'Address;
    Result: Matrix;
  begin
    Plus(L_Kludge.Actual'Access, R_Kludge.Actual'Access, Result.Actual'Access);
    return Result;
  end "+";

I won't write a diatribe here about static matching rules and records
with discriminants.  (There should be no problem with 'Access of a type
with discriminants. Do we need a 'Unbounded_Access as well?)  Well, not
a long diatribe anyway.  The example above useless as it is, compiles.
(Of course, if it is inside a declarative part.)  I could make it more
useful by putting it in a generic package with M and N as parameters,
but I think this gives a bit of the flavor.  Any sensible programmer
would have given up long ago, and passed 'Address instead.  Notice that
to make this work, I have to take 'Address of Matrix objects anyway.
(Maybe we should deprecate 'Address when used on objects which are not
aliased.  But that is also another discussion, and certainly compilers
can give a warning message.  But such a warning will only be useful, if
we fix the aliased type issue.)

****************************************************************

From: Randy Brukardt
Sent: Saturday, February 14, 2004  7:13 PM

> I'm glad I brought it up then.  As I said in my previous post, I think
> that if we really want to get aliased (and 'Access) right, there has to
> be some way for a user to declare a TYPE to be aliased.  Subtype would
> be nice, but type is important.  The problem is that right now, if an
> abstraction author wants to use access types internally, he can either
> declare a type that has aliased components and write lots of wrapper
> suprograms, or make the user declare all objects as aliased, and all the
> operations on the type must have access parameters.

Or declare the type as tagged. Since all real abstractions should be
controlled anyway, this is not a hardship. So I don't see a problem here.
(This is precisely how Claw works, and there is no difficultly using access
types internally, and it does not make the user do anything special.) But I
don't expect general agreement on this point.

****************************************************************

From: Robert I. Eachus
Sent: Saturday, February 14, 2004  8:06 PM

Well, you certainly won't get it here.  I probably should have included
the other example, which is right now compiling and passing test
programs.  But the code is bulky and still in a state of flux.  It
allows me to pass around a  view of a matrix which is a subset of a
larger matrix.  (Which is why I need the aliasing.)  Maybe at some point
I will extend it to the point of doing reference counting on the actual
matrix objects, but right now that looks like a bad direction to head.
For a large matrix I could have thousands of views in the normal course
of events.  (Applying Strassen's algorithm to matrix multiplication.)
True, the smallest view on average will be a 16x16 or so submatrix, but
there will be a lot of them.  Much easier just to use nesting to insure
that the views don't outlast the parent.

The problem with the "real" version is that the user of the package has
to declare any matrices to be passed in as aliased.  It seems much more
"Ada like" to just declare the type as aliased.  But the point you keep
missing, is that Matrices are ARRAY types, and there is no such thing in
Ada as a tagged array type.  I can have arrays in record types, but that
gets into the problems I demonstrated.  The arrays need to depend on
discriminants, and with array objects it is hard enough to get static
subtype matching.  With discriminated records it is messier.

****************************************************************

From: Robert A. Duff
Sent: Sunday, February 15, 2004  11:59 AM

> Or declare the type as tagged. Since all real abstractions should be
> controlled anyway, this is not a hardship. So I don't see a problem here.
> (This is precisely how Claw works, and there is no difficultly using access
> types internally, and it does not make the user do anything special.) But I
> don't expect general agreement on this point.

No, you won't.  ;-)

I have lots of types that uses untagged and uncontrolled types,
and I like it that way.  I'm annoyed when I have to say "tagged"
just to get aliasedness.  We can agree to disagree on this point,
but I don't think we should perturb the language design based
on one person's viewpoint as to how the language should be used.

****************************************************************

From: Robert Dewar
Sent: Monday, February 16, 2004  7:53 AM

My own view is that aliasedness is inherently evil, and personally
I find it annoying that saying "tagged" automatically gets me
this unwelcome feature.

I agree that if this nasty feature is present, it should be
orthogonal to taggedness as much as possible.

****************************************************************

From: Robert A. Duff
Sent: Monday, February 16, 2004  1:56 PM

In principle, I agree.  However, the Yogi Berra quote you mentioned
recently is relevant.  ;-)

[Editor's note: The quote was in a different thread; here it is:
"In theory there is no difference between theory and practice. In practice
there is."]

One problem is that functions can't have 'in out' parameters.
(We all know what *you* think of that -- functions can have side
effects, so long as you don't document them in the mode!)

One workaround is to use a procedure instead.  But then you
can't initialize objects at their declaration point, which is
harmful.  Also, if the function result is, say, String, you
can't use an 'out' parameter instead.  Think of something like
"function Get_Line(F: in out Input_Stream) return String".

Another workaround is to use access parameters.  But then you have to
scatter "aliased" and '[Unchecked_]Access all over the place, for things
that aren't "really" aliased -- you just want to pass things as
parameters.  This kind of "crying wolf" is also damaging.

The 'Unchecked_Access cases are particularly annoying, since "Unchecked"
is supposed to mean, "Beware!  There might be dangling pointers lurking
here", but all we're doing is passing a parameters.  If you write the
code properly, dangling pointers are impossible in these cases, but the
compiler can't help you make sure that's true.

Marking the *type* as aliased would somewhat alleviate these problems.

----------------

Another problem is that there's no syntax for declaring parameters
aliased.  You can't say:

    procedure P(X: aliased in out T) is
        Y: constant String := F(X'Unchecked_Access);

Instead, you have to make T tagged, whether it needs a tag or not.
I've had cases where this doubled the size of type T, and there
were lots of T objects at run time.

> I agree that if this nasty feature is present, it should be
> orthogonal to taggedness as much as possible.

Agreed.

The history is interesting: The MRT originally proposed that "aliased"
should be allowed for parameters.  The DR's and/or WG9 complained that
this was unnecessary complexity, so the MRT took that syntax out.
[IMHO, that kind of nonorthogonality *increases* complexity, but many
reviewers seemed to measure complexity by the amount of new syntax.]
A year or so later, the MRT discovered that aliased parameters are
really necessary in some cases, particularly for tagged types.  We
needed *some* way to get aliased parameters, so we decided that "tagged"
implies "aliased" for parameters.  No new syntax, so nobody complained.

IMHO, ``"tagged" implies "aliased" for parameters'' is not a
simplification, compared to "aliased implies aliased; say what you
mean".

P.S. It's interesting to hear "aliasedness is inherently evil" from the
inventor of the 'Unrestricted_Access attribute.  ;-)

****************************************************************

From: Randy Brukardt
Sent: Monday, February 16, 2004 11:13 PM

> I have lots of types that uses untagged and uncontrolled types,
> and I like it that way.  I'm annoyed when I have to say "tagged"
> just to get aliasedness.  We can agree to disagree on this point,
> but I don't think we should perturb the language design based
> on one person's viewpoint as to how the language should be used.

I don't quite see how saying that the status quo is good enough is going to
"perturb the language design". I'm certainly not advocating any change here!

I don't have any objection to this idea, it just doesn't seem that useful to
me, and I'm afraid of spending resources on it that could be used on
something more important (finishing pragma Assert, for instance). But, I
suspect that Tucker will ultimately decide what gets in the Amendment by
what he does or does not work on.

****************************************************************

From: Robert A. Duff
Sent: Tuesday, February 17, 2004  8:41 AM

You were arguing against a particular AI, based on your opinion that all
abstractions should be controlled.  I was just saying I don't find that
argument convincing (whether you're advocating changing the language,
or *not* changing the language -- either one is "language design"),
because that viewpoint about controlled types is far from universal.

****************************************************************

From: Robert Dewar
Sent: Wednesday, February 18, 2004  10:25 AM

> One problem is that functions can't have 'in out' parameters.
> (We all know what *you* think of that -- functions can have side
> effects, so long as you don't document them in the mode!)

I see .. so a lot of this crud is coming from wilful failure
to fix this obvious deficiency ... sort of like trying to
cater the the folks who want to do unchecked conversions but
don't allow the use of Unchecked_Conversion :-)

> P.S. It's interesting to hear "aliasedness is inherently evil" from the
> inventor of the 'Unrestricted_Access attribute.  ;-)

I am not sure that I would elevate to "invention" this minor
short hand for the use of 'Address and unchecked conversion!

P.P.S. A common use of 'Unrestricted_Access is precisely to get around
the nonsense restriction on IN/OUT parameters for functions. Though now
that I think about it, quite a few of those uses could be replaced more
cleanly by the use of pragma Import_Valued_Procedure -- DEC's neat work
around for the restriction on function IN OUT parameters.

****************************************************************

From: Randy Brukardt
Sent: Wednesday, February 18, 2004  3:31 PM

> I see .. so a lot of this crud is coming from wilful failure
> to fix this obvious deficiency ... sort of like trying to
> cater the the folks who want to do unchecked conversions but
> don't allow the use of Unchecked_Conversion :-)

Well, I tried to fix that the 'right' way (see AI-323), and we actually
discussed that at an ARG meeting - but, as we've said for many other Ada
95-discussed issues, nothing has changed, and there is insufficient will to
make the needed change.

****************************************************************

From: Tucker Taft
Sent: Monday, February 23, 2004  4:53 PM

Please note that the original basis for the proposal about "aliased" types
was to allow non-tagged types to "work right" in generics and composition.
We now require all language-defined non-limited types to have an "=" that
composes properly.  This forces the implementation of bounded strings
to require a default initialization to all nulls of the nested array.
Having the "=" for appropriately marked non-tagged types compose properly
would solve this and similar problems.

I believe the AI explains why using "aliased" as the marking for this
makes sense, and that it solves various other outstanding issues in a relatively
economical way.  The basic idea was to give the programmer more control
when they need it.  It would be helpful if rather than accusing the AI
of containing "crud designed to work around an obvious deficiency" that
reviewers read AI-304 and comment on what "crud" it actually contains. ;-)

****************************************************************

From: Randy Brukardt
Sent: Monday, February 23, 2004  5:29 PM

I certainly have sympathy with solving the "=" problem. But this solution
seems awfully heavy for just that purpose, and it seems that solving the "="
is a minor side-effect (which is backwards in my view). My initial response
to this suggestion (recorded in the !appendix) was "... seems like killing a
gnat (er, fly) with a cannon.", so that, at least, hasn't changed.

In addition, this solution to the "=" fails the "Bob Duff Orthogonality
Test". That is, you have to specify a property that you don't (necessarily)
want (in Ada 95, it's "tagged", here it would be "aliased") in order to get
the correct behavior. And "aliased" objects will generate worse code in
general (because of the assumption of aliasing, requirements for alignment,
etc.) than regular objects, so it's not something that you would not care
about using.

Moreover, having adding "aliased" to a type change the behavior of "=" seems
weird and potentially error-prone (particularly if maintenance removes
"aliased" to get better code generation).

So I remain to be convinced.

****************************************************************

From: Robert I. Eachus
Sent: Tuesday, February 24, 2004  2:11 PM

I have to agree with Tucker here.  There is a definite need for aliased
types that are not tagged types--the example of an array with aliased
components is the one that has burned me the most, but I am sure there
are others.  Allowing/requiring equality to compose "correctly" for such
types makes sense, or more to the  point, doing the opposite makes no sense.

Allowing users to declare types as aliased is a language extension, but
I don't see it as something new, I see it as a part left out of Ada 95
that is necessary to make access parameters, 'Access, and
'Unchecked_Access usable.

If some people feel that the only use for access parameters is to get
around the rule about in only parameters for functions, they are missing
all of the other things that can be done with access parameters.  And
why are they missing them?  Because the current rules make using
'Address the only possible way to do many things that a (safe) 'Access
could do.  If this AI passes, a lot of code that is currently using the
"Rosen trick" will get fixed.  Good.  It is not safe, as having a
(possibly private) type that is always passed by reference would be.  If
some want to go the whole nine yards and say that assignment to
components of a parameter of and aliased type passed by access is
allowed, I won't fight it.  But I do think that 'requiring' the type
safe version of the Rosen trick is just as good:

type Foo is aliased array....;

function Bar(X: in Foo) return Integer is
    type Foo_Pointer is access Foo;
    FP: Foo_Pointer := Foo'Access; -- or 'Unchecked_Access if required.
begin
    FP(1,1) := ...;
    return 3;
end Bar;

(I am assuming that if Foo'Access returns a value of type access to
constant, then Foo'Unchecked_Access will return access to varible. If
not we are stuck with the Rosen trick.)

Or of course, we could change the type of a random number generatior to
be aliased, and change Random to take an access parameter.  With this
AI, that is an upwardly compatible change.  Then people could use access
parameters of an aliased type where they want to insure that things are
passed by reference, and the whole religious war thing goes away.

****************************************************************

From: Randy Brukardt
Sent: Wednesday, February 25, 2004  4:27 PM

Huh? Calls to an access parameter would need 'Access (or 'Unchecked_Access) --
that hardly would be an upwardly compatible change.

It's precisely the 'noise' that access parameters force on users of an
interface that I hate. That's why I almost never use access parameters in
public interfaces -- because it puts a burden on the users of an abstraction.
'Aliased' types would reduce that burden a little, but by no means eliminate
it.

****************************************************************


Questions? Ask the ACAA Technical Agent