Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Interresting, possibly buggy behavior in GNAT generics w/ expression function.

149 views
Skip to first unread message

Shark8

unread,
Mar 28, 2013, 1:34:43 PM3/28/13
to
Lately I've been interested in perhaps getting Ada as a script-tag language, much like JavaScript. I figured I'd need a DOM library or somesuch and was looking into XMLAda (which, oddly fails compile on DOTNET-Gnat and seems oblivious to --target=JVM) so I was tinkering with it in native-code hoping to be able to get to a point where I could seek-out and alter attributes [for a node] on a DOM-Document and was surprised to find there's no functionality for altering attributes via XMLAda DOM-package (at least nothing obvious).

So I decided to play around and see about my own DOM-library (which I would rather not do, as there are several DOM-ish Ada packages about) and found this interesting tidbit: behavior changes when the parameter of image is changed from positive to natural. {Actually it only happens when Attribute_Values is instantiated with Integer[-type].}
----------------------------------------------------------------------------
With Ada.Containers.Indefinite_Vectors, Ada.Strings.Fixed;
Use Ada.Containers;

Generic
Attribute_Name : String;
Type Attribute_Values is (<>);

With Function Img(Value : Attribute_Values) Return String is Attribute_Values'Image;
With Package Units is New Indefinite_Vectors(
Index_Type => Positive,
Element_Type => String );

Attribute_Units : Units.Vector:= Units.Empty_Vector;

Package Generic_Attribute_Set is

Type Attribute(Has_Units : Boolean:= Attribute_Units.Length /= 0) is record
Value : Attribute_Values;
case Has_Units is
When True => Unit : Positive;
When False => Null;
end case;
end record;

-- The 'Image Attribute, when applied to numeric types, leaves a leading
-- space for non-negative numbers (for uniform columnuar display); this is
-- undesirable for our use, so we wrap it in a call to trim.
Function Image(Value : Attribute_Values) Return String is
( Ada.Strings.Fixed.Trim(Img(Value), Side => Ada.Strings.Left) );

-- Getting the string stored in the position for out units-vector is a
-- simple index into the proper position in the vector containing the units.
Function Image(Value : Positive) Return String is
( --if Value not in positive then "" else
Units.Constant_Reference( Attribute_Units, Value ) );

Function To_String( Attr : Attribute ) Return String is
( Attribute_Name & "=""" &
Image(Attr.Value) & (if Attr.Has_Units then Image(Attr.Unit) else "") &
'"'
);

End Generic_Attribute_Set;
----------------------------------------------------------------------------
With
Generic_Attribute_Set,
Ada.Streams,
Ada.Text_IO.Text_Streams,
Ada.Containers.Indefinite_Vectors;

Procedure Test is
Package Units is New Ada.Containers.Indefinite_Vectors(
Index_Type => Positive,
Element_Type => String );

Use Units;
Screen : Units.Vector:= Vector'("en" & "ex") & Vector'("px" & "%");

Type J is (Alpha, Beta, 'K', Fred);

Package Margins is new Generic_Attribute_Set(
Attribute_Name => "margin-left",
Attribute_Values => Integer,
Units => Units,
Attribute_Units => Screen);
Begin
Declare
Use Margins;
K : Attribute;
begin
K.Value:= 88; --J'Succ(Beta);
K.Unit:= 4;
Ada.Text_IO.Put_Line( To_String(K) );
end;
End Test;
----------------------------------------------------------------------------

As I understand it this shouldn't *ever* happen because in the generic there's supposed to be no knowledge of what the parameters are actually instantiated with.

Simon Wright

unread,
Mar 28, 2013, 2:06:39 PM3/28/13
to
As written, your code outputs 'margin-left="88%"' - looks good to me!

I think that when reporting a bug you should show

* what you did
* what happened
* what you expected to happen

Shark8

unread,
Mar 28, 2013, 2:38:11 PM3/28/13
to
Yes; now alter the Image profile from
Function Image(Value : Positive) Return String is
to
Function Image(Value : Natural) Return String is
then recompile & re-run.

That one change alters the output to margin-left="884" ... which is the problem I'm describing.

Simon Wright

unread,
Mar 29, 2013, 3:45:04 AM3/29/13
to
In Generic_Attribute_Set, you have two Image functions:

function Image(Value : Attribute_Values) return String

(Attribute_Values is a generic formal scalar) and

function Image(Value : Positive) return String

and you instantiate the package with Attribute_Values => Integer.

What happens when you change the second Image's parameter to Integer is
that GNAT chooses the wrong Image to call!

I don't know whether this is a language problem or a GNAT problem. Or,
of course, a user problem!

(It's not a problem with statement functions; the same happens if the
function implementations are moved to the body).

Dmitry A. Kazakov

unread,
Mar 29, 2013, 8:27:17 AM3/29/13
to
On Fri, 29 Mar 2013 07:45:04 +0000, Simon Wright wrote:

> I don't know whether this is a language problem

It is a general language problem that generic specifications and bodies
cannot be fully checked. Matched formal parameters only is not sufficient.
Much better than with C++ templates, but still same mess.

--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de

Simon Wright

unread,
Mar 29, 2013, 10:45:33 AM3/29/13
to
"Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> writes:

> On Fri, 29 Mar 2013 07:45:04 +0000, Simon Wright wrote:
>
>> I don't know whether this is a language problem
>
> It is a general language problem that generic specifications and bodies
> cannot be fully checked. Matched formal parameters only is not sufficient.
> Much better than with C++ templates, but still same mess.

But, do you think it should have failed at instantiation? Not good, but
not as bad as executing the wrong code.

Shark8

unread,
Mar 29, 2013, 10:47:23 AM3/29/13
to
On Friday, March 29, 2013 1:45:04 AM UTC-6, Simon Wright wrote:
> In Generic_Attribute_Set, you have two Image functions:
>
> function Image(Value : Attribute_Values) return String
>
> (Attribute_Values is a generic formal scalar) and
>
> function Image(Value : Positive) return String
>
> and you instantiate the package with Attribute_Values => Integer.
>
>
> What happens when you change the second Image's parameter to Integer is
> that GNAT chooses the wrong Image to call!

Yes; hence the 'interesting' and 'possibly buggy'.

>
> I don't know whether this is a language problem or a GNAT problem. Or,
> of course, a user problem!

This is precisely why I posted it here rather than instantly filing a bug-report.

On the other hand it seems to violate the generic-parameters/principal that we can only apply operations (Attributes and Operations) which the formal is *known* to have.

Simon Wright

unread,
Mar 29, 2013, 10:47:36 AM3/29/13
to
Shark8 <onewing...@gmail.com> writes:

> Function Image(Value : Positive) Return String is
> ( --if Value not in positive then "" else
> Units.Constant_Reference( Attribute_Units, Value ) );

Or, of course, Attribute_Units (Value) !

Shark8

unread,
Mar 29, 2013, 10:54:44 AM3/29/13
to
That doesn't work.
That I'm pretty sure is a bug; in any case at least the [compile-time] error it gives is utterly useless:
generic_attribute_set.ads:36:07: "" is undefined

Shark8

unread,
Mar 29, 2013, 10:56:54 AM3/29/13
to
On Friday, March 29, 2013 8:47:23 AM UTC-6, Shark8 wrote:
> On Friday, March 29, 2013 1:45:04 AM UTC-6, Simon Wright wrote:
>
> > In Generic_Attribute_Set, you have two Image functions:
> >
> > function Image(Value : Attribute_Values) return String
> >
> > (Attribute_Values is a generic formal scalar) and
> >
> > function Image(Value : Positive) return String
> >
> > and you instantiate the package with Attribute_Values => Integer.
> >
> >
> > What happens when you change the second Image's parameter to Integer is
> > that GNAT chooses the wrong Image to call!

But, what's odd is that the parameter works on one when "positive" and fails when "natural" -- that is, I think, the far more puzzling behavior.

Bill Findlay

unread,
Mar 29, 2013, 11:26:51 AM3/29/13
to
On 29/03/2013 14:54, in article
615039cc-f33b-486a...@googlegroups.com, "Shark8"
Type resolution in conditional expressions by GNAT GPL 2012 is not all it
should be. E.g. I had to make the second 0 into a qualified expression in:

function XR (X : M.i04)
return M.i64 is
begin
return (if X = 0 then M.i64'(0) else GR(X));
end XR;

because GNAT could not otherwise deduce its intended type, even though GR(X)
is of type M.i64.

Further to bijou buglettes in Ada 2012 mode, I had to write this:

for s in slice'Range loop
exit when slice(s) = all_blanks_code;
h := rotate_left(h, 2) + slice(s);
end loop;

To avoid this:

for s of slice loop
exit when s = all_blanks_code;
|
>>> warning: variable "s" is not modified in loop body
>>> warning: possible infinite loop

h := rotate_left(h, 2) + s;
end loop;

--
Bill Findlay
with blueyonder.co.uk;
use surname & forename;


Simon Wright

unread,
Mar 29, 2013, 11:48:21 AM3/29/13
to
With GCC 4.7.0, it gives a bug box.
With GNAT GPL 2012, as you say.
With GCC 4.8.0 (release candidate r196827) it works fine.

Dmitry A. Kazakov

unread,
Mar 29, 2013, 12:21:39 PM3/29/13
to
On Fri, 29 Mar 2013 14:45:33 +0000, Simon Wright wrote:

> "Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> writes:
>
>> On Fri, 29 Mar 2013 07:45:04 +0000, Simon Wright wrote:
>>
>>> I don't know whether this is a language problem
>>
>> It is a general language problem that generic specifications and bodies
>> cannot be fully checked. Matched formal parameters only is not sufficient.
>> Much better than with C++ templates, but still same mess.
>
> But, do you think it should have failed at instantiation?

It should fail to compile, instantiation time is too late. Generic
contracts are much too weak.

For example:

generic
type S is new T with private;
package P is
type Q is new S with null record;
not overriding procedure Foo (X : Q);

It is uncheckable if S does not have Foo already. Thus, this must be a
compile error.

If we wanted properly contracted generics (personally, I don't care), we
would need some syntax to tell that S may not have operation Foo, e.g.

generic
type S is new T with private;
not with procedure Foo (X : S);
package P is
type Q is new S with null record;
not overriding procedure Foo (X : Q); -- We know S does not have this

Shark8

unread,
Mar 29, 2013, 12:43:35 PM3/29/13
to mai...@dmitry-kazakov.de
On Friday, March 29, 2013 10:21:39 AM UTC-6, Dmitry A. Kazakov wrote:
> On Fri, 29 Mar 2013 14:45:33 +0000, Simon Wright wrote:
>
> > "Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> writes:
> >
> >> On Fri, 29 Mar 2013 07:45:04 +0000, Simon Wright wrote:
> >>
> >>> I don't know whether this is a language problem
> >>
> >> It is a general language problem that generic specifications and bodies
> >> cannot be fully checked. Matched formal parameters only is not sufficient.
> >> Much better than with C++ templates, but still same mess.
> >
> > But, do you think it should have failed at instantiation?
>
>
> It should fail to compile, instantiation time is too late. Generic
> contracts are much too weak.

I'm not sure I believe that [they are too weak] -- in any case this isn't a problem of the weakness of generics, it's a case of the compiler choosing a function which it should not dependent upon information it should not "know".

Keeping the instantiation of
Package Margins is new Generic_Attribute_Set(
Attribute_Name => "margin-left",
Attribute_Values => Integer, --J,
Attribute_Units => Screen,
Units => Units
);
altering the profile of Image [in the generic]
from: Function Image(Value : Positive) Return String is
to: Function Image(Value : Natural) Return String is
alters the behavior
from: margin-left="88%"
to: margin-left="884"

The issue disappears entirely if an enumeration is supplied for attribute_values so that the correct Image is chosen in either case of Image/Natural or Image/Positive.

>
> For example:
>
> generic
> type S is new T with private;
> package P is
> type Q is new S with null record;
> not overriding procedure Foo (X : Q);
>
> It is uncheckable if S does not have Foo already. Thus, this must be a
> compile error.
>
> If we wanted properly contracted generics (personally, I don't care), we
> would need some syntax to tell that S may not have operation Foo, e.g.
>
> generic
> type S is new T with private;
> not with procedure Foo (X : S);
> package P is
> type Q is new S with null record;
>

That's a good point, perhaps you should submit an AI?

Eryndlia Mavourneen

unread,
Mar 29, 2013, 1:43:05 PM3/29/13
to mai...@dmitry-kazakov.de
I agree that generics are too weak. It seems that I frequently am trying to use a generic formal parameter's characteristics, but the compiler reminds me that the characteristic is unknown (until instantiation), and so the compilation of the generic fails. Indices are a good example. I am not sure about 'Range. That might work.

-- Eryndlia

Eryndlia Mavourneen

unread,
Mar 29, 2013, 1:45:37 PM3/29/13
to mai...@dmitry-kazakov.de
I do realize, of course, that indices can be specified as formal parameters, but that is a lot of hassle. I seem to recall that there were other issues, too, that failed in compiling an generic unit.

-- Eryndlia

Simon Wright

unread,
Mar 29, 2013, 2:38:31 PM3/29/13
to
Eryndlia Mavourneen <eryn...@gmail.com> writes:

> I do realize, of course, that indices can be specified as formal
> parameters, but that is a lot of hassle.

Necessary hassle.

Randy Brukardt

unread,
Mar 29, 2013, 8:56:05 PM3/29/13
to
"Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> wrote in message
news:1ex3dm2hk2j54$.1uiyljwziv0hi$.dlg@40tude.net...
...
>> But, do you think it should have failed at instantiation?
>
> It should fail to compile, instantiation time is too late. Generic
> contracts are much too weak.

This doesn't make much sense, as you then go on to suggest adding a formal
contract which would have the effect of rejecting an instantiation if the
type actually had Foo. That's exactly what Ada does, so I don't see any
advantage of a complication.

The problem you are having is that you are viewing the contract of a generic
in too narrow of a fashion. The contract includes not only the things in the
generic part, but also a number of properties expressed in the rest of the
specification. After all, almost all Ada legality rules are rechecked in
instance specifications, and these too have to be considered part of the
contract.

Randy.


Randy Brukardt

unread,
Mar 29, 2013, 9:04:28 PM3/29/13
to
"Simon Wright" <si...@pushface.org> wrote in message
news:lysj3ei...@pushface.org...
> In Generic_Attribute_Set, you have two Image functions:
>
> function Image(Value : Attribute_Values) return String
>
> (Attribute_Values is a generic formal scalar) and
>
> function Image(Value : Positive) return String
>
> and you instantiate the package with Attribute_Values => Integer.
>
> What happens when you change the second Image's parameter to Integer is
> that GNAT chooses the wrong Image to call!

Something is wrong with this description, because as you have described it,
any call on Image should be ambiguous and thus illegal. Specifically:

generic
type Attribute_Values is (<>);
package Test_It is
function Image(Value : Attribute_Values) return String;
function Image(Value : Positive) return String;
end Test_It;

package A_Test is new Test_It (Integer);

This instantiation is legal. However, a call like
A_Test.Image (10);
is ambiguous, because there is no possible way to know which routine should
be called. It's certainly not possible to call the *wrong* one here, because
they are exactly the same for resolution purposes.

Now, if they have different parameter names:
function Image (Val : Positive) return String;
then
A_Test.Image (Val => 10); -- Should work.
A_Test.Image (10); -- Still ambiguous.

If GNAT is allowing these calls, *that's* the bug; what happens when you
change subtypes is irrelevant.

Perhaps you guys would like to do as you are always griping to others and
provide a complete enough example to see what you are really talking
about???

Randy.




Shark8

unread,
Mar 29, 2013, 10:36:20 PM3/29/13
to
On Friday, March 29, 2013 7:04:28 PM UTC-6, Randy Brukardt wrote:
> "Simon Wright" <si...@pushface.org> wrote in message
>
> news:lysj3ei...@pushface.org...
>
> > In Generic_Attribute_Set, you have two Image functions:
> > function Image(Value : Attribute_Values) return String
> >
> > (Attribute_Values is a generic formal scalar) and
> >
> > function Image(Value : Positive) return String
> >
> > and you instantiate the package with Attribute_Values => Integer.
> >
> > What happens when you change the second Image's parameter to Integer is
> > that GNAT chooses the wrong Image to call!
>
>
> Something is wrong with this description, because as you have described it,
> any call on Image should be ambiguous and thus illegal. Specifically:

Hm, interesting -- I would have thought the other way: that the Image operating on the generic-formal's type would be called only when the value/variable was definitely it's own type rather than possibly its own type.

The To_String function, which calls both image-routines is:
Image(Attr.Value) & -- Certainly the formal variant.
(if Attr.Has_Units then Image(Attr.Unit) -- Certainly the integral version.
else "") -- Certainly a string.

These two calls converge in one case and diverge on the other (when [a] instantiated by Integer, and [b] dependent on the parameter being natural or positive).

Not disagreeing w/ you, just explaining that it seems this shouldn't happen -- and you're assertion that this should be illegal [ambiguity] would indeed prevent it.

> generic
> type Attribute_Values is (<>);
> package Test_It is
> function Image(Value : Attribute_Values) return String;
> function Image(Value : Positive) return String;
> end Test_It;
>
> package A_Test is new Test_It (Integer);
>
> This instantiation is legal. However, a call like
> A_Test.Image (10);
> is ambiguous, because there is no possible way to know which routine should
> be called. It's certainly not possible to call the *wrong* one here, because
> they are exactly the same for resolution purposes.

I see what you're saying.

> Now, if they have different parameter names:
> function Image (Val : Positive) return String;
> then
> A_Test.Image (Val => 10); -- Should work.
>
> A_Test.Image (10); -- Still ambiguous.
>
> If GNAT is allowing these calls, *that's* the bug; what happens when you
> change subtypes is irrelevant.

Indeed, that's what's so puzzling. The WHY of it; I could see your explanation above, and see raising an error about it -- but in this case altering the subtype DOES alter behavior -- and it should not because the type of both is exactly the same.

>
> Perhaps you guys would like to do as you are always griping to others and
> provide a complete enough example to see what you are really talking
> about???

I thought I had w/ my first post...

Stephen Leake

unread,
Mar 30, 2013, 1:59:47 AM3/30/13
to
Yes, that looks like a GNAT compiler bug.

Note that it would have been clearer if you had posted the version of
the code that gives incorrect results.

It would also help if you used the conventional style of making reserved
words all lowercase.

--
-- Stephe

Dmitry A. Kazakov

unread,
Mar 30, 2013, 5:24:05 AM3/30/13
to
On Fri, 29 Mar 2013 19:56:05 -0500, Randy Brukardt wrote:

> "Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> wrote in message
> news:1ex3dm2hk2j54$.1uiyljwziv0hi$.dlg@40tude.net...
> ...
>>> But, do you think it should have failed at instantiation?
>>
>> It should fail to compile, instantiation time is too late. Generic
>> contracts are much too weak.
>
> This doesn't make much sense, as you then go on to suggest adding a formal
> contract which would have the effect of rejecting an instantiation if the
> type actually had Foo. That's exactly what Ada does, so I don't see any
> advantage of a complication.

That is because you consider only one possibility, that is a client-side
error. Then instantiation is the right time to report this contract
violation. For the generic package itself this time is when the generic is
compiled.

My example had the purpose to show that matching formal parameters is not
enough. It could illustrate an error in the generic itself as well, e.g.
when *all* intended actual types for instantiations of P have Foo per
design.

> The problem you are having is that you are viewing the contract of a generic
> in too narrow of a fashion. The contract includes not only the things in the
> generic part, but also a number of properties expressed in the rest of the
> specification.

You lumped together two different contracts. There is a contract on the
actual parameters which is defined by be the formal parameters
specification. Another contract is the generic package specification
(public part), which is a contract for the clients using an instance of the
package.

Shark8

unread,
Mar 30, 2013, 10:20:32 AM3/30/13
to
On Friday, March 29, 2013 11:59:47 PM UTC-6, Stephen Leake wrote:
>
> Note that it would have been clearer if you had posted the version of
> the code that gives incorrect results.

Granted; though I thought I was fairly clear the puzzling thing was that the alteration of the parameter-type, between two subtypes [derived from the same type(!)], was the interesting/weird ting... and in order to see that you'd have to try both alternatives anyway.

Simon Wright

unread,
Mar 30, 2013, 11:51:52 AM3/30/13
to
"Randy Brukardt" <ra...@rrsoftware.com> writes:

> Perhaps you guys would like to do as you are always griping to others
> and provide a complete enough example to see what you are really
> talking about???

I'm not sure whether this is exactly the same:

generic
type Attribute_Values is (<>);
package Demo is
function Text (Item : Character) return String;
private
function Image (Item : Attribute_Values) return String;
function Image (Item : Positive) return String;
end Demo;

package body Demo is
function Text (Item : Character) return String is
begin
return Image (Integer (Character'Pos (Item)))
& " "
& Image (Positive (Character'Pos (Item)));
end Text;
function Image (Item : Attribute_Values) return String is
begin
return (1 => Character'Val (Attribute_Values'Pos (Item)));
end Image;
function Image (Item : Positive) return String is
begin
return Positive'Image (Item);
end Image;
end Demo;

with Demo;
with Ada.Text_IO; use Ada.Text_IO;
procedure Demo_Main is
package Integers is new Demo (Attribute_Values => Integer);
begin
Put_Line (Integers.Text ('a'));
end Demo_Main;

outputs

a 97

where we would have expected

97 97

Adam Beneschan

unread,
Apr 1, 2013, 11:58:09 AM4/1/13
to
Randy, it looks to me that the original code called Image(...) only from inside the generic specification or body, not outside.

I'm sure Randy already knows this, but for the benefit of anyone who doesn't: When a call to Image occurs inside the generic spec or body, the meaning of Image (i.e. which one is selected) depends only on the stuff the compiler knows when the generic is *compiled*; the actual types used in an *instantiation* don't matter, for this purpose. (Yes, I know things might be a bit more complicated when dispatching is involved, but that's not an issue here.) For compilers that use "macro expansion" to implement generic instantiations (including GNAT, but not Janus/Ada), this poses challenges for the compiler writer, because it doesn't work to simply replace Attribute_Values with Integer when recompiling the generic. This looks like a case that fell through the cracks in GNAT.

-- Adam

Randy Brukardt

unread,
Apr 1, 2013, 8:46:06 PM4/1/13
to
"Adam Beneschan" <ad...@irvine.com> wrote in message
news:65330bfe-39e4-4f7b...@googlegroups.com...
On Friday, March 29, 2013 6:04:28 PM UTC-7, Randy Brukardt wrote:

...
>Randy, it looks to me that the original code called Image(...) only from
>inside the
>generic specification or body, not outside.

OK, I didn't see that, because the OP I got only had a description of the
spec in it, no code at all.

>I'm sure Randy already knows this, but for the benefit of anyone who
>doesn't: When
>a call to Image occurs inside the generic spec or body, the meaning of
>Image (i.e.
>which one is selected) depends only on the stuff the compiler knows when
>the
>generic is *compiled*; the actual types used in an *instantiation* don't
>matter,
>for this purpose. (Yes, I know things might be a bit more complicated when
>dispatching is involved, but that's not an issue here.) For compilers that
>use
>"macro expansion" to implement generic instantiations (including GNAT, but
>not
>Janus/Ada), this poses challenges for the compiler writer, because it
>doesn't work
>to simply replace Attribute_Values with Integer when recompiling the
>generic. This
>looks like a case that fell through the cracks in GNAT.

Right. Calls in the body *always* should treat Attr_Value and
Natural/Positive as different types; the actuals don't matter. So if
changing the subtypes is changing the called routines, you have a GNAT bug,
pure and simple.

Randy.


Randy Brukardt

unread,
Apr 1, 2013, 8:52:10 PM4/1/13
to
"Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> wrote in message
news:1ilubaaaex6jp$.zd9lslst85nn.dlg@40tude.net...
> On Fri, 29 Mar 2013 19:56:05 -0500, Randy Brukardt wrote:
>
>> "Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> wrote in message
>> news:1ex3dm2hk2j54$.1uiyljwziv0hi$.dlg@40tude.net...
>> ...
>>>> But, do you think it should have failed at instantiation?
>>>
>>> It should fail to compile, instantiation time is too late. Generic
>>> contracts are much too weak.
>>
>> This doesn't make much sense, as you then go on to suggest adding a
>> formal
>> contract which would have the effect of rejecting an instantiation if the
>> type actually had Foo. That's exactly what Ada does, so I don't see any
>> advantage of a complication.
>
> That is because you consider only one possibility, that is a client-side
> error. Then instantiation is the right time to report this contract
> violation. For the generic package itself this time is when the generic is
> compiled.
>
> My example had the purpose to show that matching formal parameters is not
> enough. It could illustrate an error in the generic itself as well, e.g.
> when *all* intended actual types for instantiations of P have Foo per
> design.

True. But I don't think it is possible to unambiguously tell which side of
the contract is wrong, in general. You have the same problem with a
subprogram profile: it's possible that the error is that the subprogram is
wrong for its intended use, or that the clients are using it wrong.

>> The problem you are having is that you are viewing the contract of a
>> generic
>> in too narrow of a fashion. The contract includes not only the things in
>> the
>> generic part, but also a number of properties expressed in the rest of
>> the
>> specification.
>
> You lumped together two different contracts. There is a contract on the
> actual parameters which is defined by be the formal parameters
> specification. Another contract is the generic package specification
> (public part), which is a contract for the clients using an instance of
> the
> package.

No I didn't - I'm only talking about the contract of a generic unit. The
case in question is the meaning of "not overriding" in a generic
speecification. Uses of overriding indicators in a generic specification is
part of the contract of the generic, as are various other things (like
accessibility checks - it's easy to write a generic that can only be
instantiated at library level). The contract of a generic also includes the
things in generic formal part (between "generic" and "package"). None of
this has anything to do with parameters - I don't know what gave you that
idea.

Randy.



Simon Wright

unread,
Apr 2, 2013, 4:18:36 AM4/2/13
to
"Randy Brukardt" <ra...@rrsoftware.com> writes:

> OK, I didn't see that, because the OP I got only had a description of
> the spec in it, no code at all.

Actually, it was complete; it used expression functions. Fooled me, too,
at first.

Dmitry A. Kazakov

unread,
Apr 2, 2013, 4:51:31 AM4/2/13
to
On Mon, 1 Apr 2013 19:52:10 -0500, Randy Brukardt wrote:

> "Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> wrote in message
> news:1ilubaaaex6jp$.zd9lslst85nn.dlg@40tude.net...

>> You lumped together two different contracts. There is a contract on the
>> actual parameters which is defined by be the formal parameters
>> specification. Another contract is the generic package specification
>> (public part), which is a contract for the clients using an instance of
>> the package.
>
> No I didn't - I'm only talking about the contract of a generic unit.

It is more than one contract because a generic unit is used in two
completely different contexts:

1. Instantiation

2. Use of the instance

> The
> case in question is the meaning of "not overriding" in a generic
> speecification. Uses of overriding indicators in a generic specification is
> part of the contract of the generic, as are various other things (like
> accessibility checks - it's easy to write a generic that can only be
> instantiated at library level).

Considering the contract #1 it is a language design error. This contract
should be limited strictly to the formal part, IMO. Impossibility to
achieve that is one of multiple problems all macro expansions have (Ada
generics included).

Stephen Leake

unread,
Apr 2, 2013, 7:14:30 AM4/2/13
to
"Randy Brukardt" <ra...@rrsoftware.com> writes:

> "Adam Beneschan" <ad...@irvine.com> wrote in message
> news:65330bfe-39e4-4f7b...@googlegroups.com...
> On Friday, March 29, 2013 6:04:28 PM UTC-7, Randy Brukardt wrote:
>
> ...
>>Randy, it looks to me that the original code called Image(...) only from
>>inside the
>>generic specification or body, not outside.
>
> OK, I didn't see that, because the OP I got only had a description of the
> spec in it, no code at all.

The code is in function expressions in the spec; no body required.

--
-- Stephe

Randy Brukardt

unread,
Apr 2, 2013, 5:59:12 PM4/2/13
to
"Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> wrote in message
news:1nrmzafa783kj.b...@40tude.net...
> On Mon, 1 Apr 2013 19:52:10 -0500, Randy Brukardt wrote:
>
>> "Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> wrote in message
>> news:1ilubaaaex6jp$.zd9lslst85nn.dlg@40tude.net...
>
>>> You lumped together two different contracts. There is a contract on the
>>> actual parameters which is defined by be the formal parameters
>>> specification. Another contract is the generic package specification
>>> (public part), which is a contract for the clients using an instance of
>>> the package.
>>
>> No I didn't - I'm only talking about the contract of a generic unit.
>
> It is more than one contract because a generic unit is used in two
> completely different contexts:
>
> 1. Instantiation
>
> 2. Use of the instance

I was only talking about the first.

>> The case in question is the meaning of "not overriding" in a generic
>> speecification. Uses of overriding indicators in a generic specification
>> is
>> part of the contract of the generic, as are various other things (like
>> accessibility checks - it's easy to write a generic that can only be
>> instantiated at library level).
>
> Considering the contract #1 it is a language design error. This contract
> should be limited strictly to the formal part, IMO. Impossibility to
> achieve that is one of multiple problems all macro expansions have (Ada
> generics included).

It would have been nice to keep the contract solely in the formal part, but
it would have been way too complex to do that. (You'd have to have contracts
for accessibility and overriding and a load of other things.)

Since the instantiation contract can't be practically kept solely in the
formal part, it would have been better to say from the begining that the
entire specification participates in the contract (that is, have less
separation). The existing syntax seems to imply that which cannot be
delivered. Perhaps somehow marking contract items in the specification would
have been a better plan.

Anyway, we're stuck with the mess now. Thank Tucker for that. :-)
[Rechecking in the instance was an Ada 95 invention.]

Randy.


Randy Brukardt

unread,
Apr 2, 2013, 6:00:54 PM4/2/13
to
"Stephen Leake" <stephe...@stephe-leake.org> wrote in message
news:85k3olb...@stephe-leake.org...
The message I saw had no specification in it either, just some text
describing the problem. There was no Ada code at all other than a one liner
declaration of Image.

Randy.


Adam Beneschan

unread,
Apr 2, 2013, 7:01:46 PM4/2/13
to
On Tuesday, April 2, 2013 3:00:54 PM UTC-7, Randy Brukardt wrote:

> The message I saw had no specification in it either, just some text
> describing the problem. There was no Ada code at all other than a one liner
> declaration of Image.

If you still haven't seen it, this link should bring it up: https://groups.google.com/d/msg/comp.lang.ada/VW5bGBVN94g/8B26b3Dgq9QJ

-- Adam

Randy Brukardt

unread,
Apr 3, 2013, 8:08:52 PM4/3/13
to
"Adam Beneschan" <ad...@irvine.com> wrote in message
news:2103bcbc-19e2-4fcf...@googlegroups.com...
It looks like the first message I saw was Simon's reply to this -- I think
they came up as separate threads for some reason and I never realized that
this code has anything to do with the reply.

Randy.


0 new messages