From: Randy Brukardt on
"Hibou57 (Yannick Duch�ne)" <yannick_duchene(a)yahoo.fr> wrote in message
news:4e959c35-34d1-49fb-b1eb-5b298e42610f(a)z19g2000yqk.googlegroups.com...
>On 9 f�v, 15:47, Robert A Duff <bobd...(a)shell01.TheWorld.com> wrote:
>> I agree that it's good to avoid heap management when possible.
>> But why can't you declare local variables of type My_Interface'Class,
>> initialized with build-in-place function calls?
>
>Synchronized-and-the-like interface types are limited, so the built-in-
>place is indeed really built-in-place (no kind of conversion allowed
>at any stage). The initializer function have to return a class wide
>and return it using an extended return statement which is required to
>return the same exact type/subtype as the one function returns.
>
>This way of doing thing is not compatible with the implementation-
>hiding requirement, as it would require the implementation type to be
>exposed in the public part, so that I could define a public function
>returning this exact type.

I don't buy this at all. The exact types to create can be selected by many
means (presumably by the parameters). You can use a dispatching constructor
function in the concrete types, using the factory pattern
(Generic_Dispatching_Constructor), and roughly organized as Bob noted.

Note that you have this problem with *any* constructor of any tagged type if
you have any interest at all in allowing future extensions.

It would be nice to have a container for Classwide limited types as the
problem comes up frequently. We made some initial efforts in that direction
but had problems with finalization and readability of the results. We then
turned our attention to those building-block problems and never did come
back to the limited containers themselves. I suspect that we could do a very
usable job with the new syntax magic for iterators, accessors, and the like.
(Presuming that we got those to work out, not there yet.)

Randy.


From: Hibou57 (Yannick Duchêne) on
On 10 fév, 00:29, Robert A Duff <bobd...(a)shell01.TheWorld.com> wrote:
> I don't understand the problem.  The following should work.
> Doesn't it do what you want?  Type T exports Public,
> but hides Hidden.  No heap allocation.
>
>  package P is
>     type T is synchronized interface;
>     function Create return T'Class;
>
>     procedure Public (X : in out T) is abstract;
>
>  private
>
>     protected type T2 is new T with
>        overriding entry Public;
>        entry Hidden;
>     end T2;
>
>  end P;
>
>  package body P is
>     function Create return T'Class is
>     begin
>        return Result : T2 do
>           ...
>        end return;
>     end Create;
>
>     protected body T2 is
>        entry Public when ... is
>        begin
>           ...
>        end Public;
>
>        entry Hidden when ... is
>        begin
>           ...
>        end Hidden;
>     end T2;
>
>  end P;
>
>  with P; use P;
>  procedure Main is
>
>     X : T'Class := Create;
>
>  begin
>     Public (X);
>  end Main;
>
> - Bob

This was exactly what I've tried, except that I used something like “
return Result : T'Class := ... do ” instead of “ return Result : T2 do
”, which is not legal, as stated by the ARM :

[ARM 6.5(5.2/2)]
If the result subtype of the function is defined by a subtype_mark,
the return_subtype_indication shall be a subtype_indication.

Ok for this one, but later it's going wrong :

Remainder of [ARM 6.5(5.2/2)]
The type of the subtype_indication shall be the result type of the
function.

But T2, in the return statement, is not T'Class, in the function
return type indication. And indeed, when I've tried your way, GNAT
complained “ wrong type for return_subtype_indication ”

So it must be T'Class in the return statement, and as by both

[ARM 6.5(5.d/2)]
Discussion: We know that if the result type is class wide, then there
must be an expression of the return statement.

and

[ARM 6.5(5.5/2)]
If the result subtype of the function is limited, then the expression
of the return statement (if any) shall be an aggregate, a function
call (or equivalent use of an operator), or a qualified_expression or
parenthesized expression whose operand is one of these.

an initialization is required (otherwise the concret type of the
object would be unknown).

I was failing there, as there is no kind of extention aggregate for a
protected type (it's not a record, although tagged).

But I've finally solved the trick : see next reply to Randy.
On 10 fév, 00:29, Robert A Duff <bobd...(a)shell01.TheWorld.com> wrote:
> I don't understand the problem.  The following should work.
> Doesn't it do what you want?  Type T exports Public,
> but hides Hidden.  No heap allocation.
>
>  package P is
>     type T is synchronized interface;
>     function Create return T'Class;
>
>     procedure Public (X : in out T) is abstract;
>
>  private
>
>     protected type T2 is new T with
>        overriding entry Public;
>        entry Hidden;
>     end T2;
>
>  end P;
>
>  package body P is
>     function Create return T'Class is
>     begin
>        return Result : T2 do
>           ...
>        end return;
>     end Create;
>
>     protected body T2 is
>        entry Public when ... is
>        begin
>           ...
>        end Public;
>
>        entry Hidden when ... is
>        begin
>           ...
>        end Hidden;
>     end T2;
>
>  end P;
>
>  with P; use P;
>  procedure Main is
>
>     X : T'Class := Create;
>
>  begin
>     Public (X);
>  end Main;
>
> - Bob

This was exactly what I've tried, except that I used something like “
return Result : T'Class := ... do ” instead of “ return Result : T2 do
”, which is not legal, as stated by the ARM :

[ARM 6.5(5.2/2)]
If the result subtype of the function is defined by a subtype_mark,
the return_subtype_indication shall be a subtype_indication.

Ok for this one, but later it's going wrong :

Remainder of [ARM 6.5(5.2/2)]
The type of the subtype_indication shall be the result type of the
function.

But T2, in the return statement, is not T'Class, in the function
return type indication. And indeed, when I've tried your way, GNAT
complained “ wrong type for return_subtype_indication ”

So it must be T'Class in the return statement, and as by both

[ARM 6.5(5.d/2)]
Discussion: We know that if the result type is class wide, then there
must be an expression of the return statement.

and

[ARM 6.5(5.5/2)]
If the result subtype of the function is limited, then the expression
of the return statement (if any) shall be an aggregate, a function
call (or equivalent use of an operator), or a qualified_expression or
parenthesized expression whose operand is one of these.

an initialization is required (otherwise the concret type of the
object would be unknown).

I was failing there, as there is no kind of extention aggregate for a
protected type (it's not a record, although tagged).

But I've finally solved the trick : see next, in the reply to Randy

On 10 fév, 03:39, "Randy Brukardt" <ra...(a)rrsoftware.com> wrote:
> I don't buy this at all. The exact types to create can be selected by many
> means (presumably by the parameters). You can use a dispatching constructor
> function in the concrete types, using the factory pattern
> (Generic_Dispatching_Constructor), and roughly organized as Bob noted.
What confused me, was I meet with initialization of a class wide type
whose initializer was to of a protected type, as explained in the
reply to Robert/Bob.

I could finally solve it, using a function, instead of an aggregate.

> Note that you have this problem with *any* constructor of any tagged type if
> you have any interest at all in allowing future extensions.
While tagged record and tagged protected is not fully the same, as
this example shows.

Well, finally the previous assertion is canceled, and there is indeed
a nice and clean way to do things with a synchronized interface type.

Thanks to the one who suggested this path.
From: Hibou57 (Yannick Duchêne) on
On 10 fév, 06:12, Hibou57 (Yannick Duchêne) <yannick_duch...(a)yahoo.fr>
wrote:
> What confused me, was I meet with initialization of a class wide type
> whose initializer was to of a protected type, as explained in the
> reply to Robert/Bob.
>
> I could finally solve it, using a function, instead of an aggregate.
Unfortunately, this was working only when the interface type is
"implemented" by a protected type, but as soon as I want to apply the
same scheme with a task type "implementing" the interface, then GNAT
crashes (it says Program_Error EXCEPTION_ACCESS_VIOLATION).
Not lucky
From: Adam Beneschan on
On Feb 9, 6:56 am, Robert A Duff <bobd...(a)shell01.TheWorld.com> wrote:
> AdaMagica <christoph.gr...(a)eurocopter.com> writes:
> > OK, but then you have a similar problem to Ada83's syntactically
> > unneeded bodies which Ada95 solved with a pragma.
>
> I think that problem is an illusion.  There was a problem,
> but it was a problem with implementations, not with the
> language.  How do we know if a given package spec has
> a body?  Simple: look on the disk and see if there's
> a source file containing that body.  In GNAT, that would
> mean looking for foo.adb.

And for other implementations (that put fewer restrictions on the
names and locations of source files containing the Ada source), that
would mean searching every file on the disk to see if one of them had
"package body foo" in it. :) :)

I know---those other implementations wouldn't do things this way;
they'd provide some other mechanism to allow a programmer to tell the
compilation system that a package no longer requires a body---or does
require a body. But you should be careful when you say things like
"Simple...". Unless, of course, you were joking. Anyway, the problem
was certainly solvable in any implementation, although as Randy points
out it's still not ideal because it makes it too easy for an
accidental error to result in the compiler accepting a package without
a body that's supposed to have one, or vice versa, causing incorrect
results at runtime that could be puzzling to track down. And that
issue exists with GNAT also---you delete some files from your
directory with a wildcard, somehow foo.adb accidentally gets deleted
along with them, and the compiler still thinks your program is OK.

-- Adam
From: Robert A Duff on
"Hibou57 (Yannick Duch�ne)" <yannick_duchene(a)yahoo.fr> writes:

> Remainder of [ARM 6.5(5.2/2)]
> The type of the subtype_indication shall be the result type of the
> function.

Ah, I see the problem. This is a mistake in the RM, and there's
an AI that fixes it. The real rule is that (in my example) T2
must be covered by T'Class, which it is.

Recent versions of GNAT correctly implement this new rule,
but I don't know what version you're using.

- Bob