Google Groupes n'accepte plus les nouveaux posts ni abonnements Usenet. Les contenus de l'historique resteront visibles.

Package's private parts and protected types

8 vues
Accéder directement au premier message non lu

Hibou57 (Yannick Duchêne)

non lue,
7 févr. 2010, 23:30:3007/02/2010
à
Hi all out there,

Whenever a protected type is declared, all of its specification has to
be defined at once and not private stuff can be delay (like "type ...
is private" would allow). If this protected type is to hold something
which is not to be public, the only way to do as far I'm able to do,
is to wrap it in a private type as a record component.

package P

type A_Type is limited private;
-- Must be limited, to be able to hold a limited component.

function Value (A : A_Type) return Value_Type;
-- Value_Type defined somewhere else.

procedure Do_Something (A : in out A_Type);
-- Potentially blocking.
-- Obviously, there are comments to assert such things,
-- but I would prefer it to be formally stated.

private

protected type B_Type is
-- Cannot move it in the public part, due
-- to a feature (Set_Value) which must not be public.
function Value return Value_Type;
-- Accessed via the corresponding method on A_Type.
procedue Set_Value (New_Value : in Value_Type);
-- The A_Type does not have such a corresponding
-- method : we want it to remains private.
procedure Do_Something;
-- Accessed via the corresponding method on A_Type.
-- B_Type being protected, this means this is
-- a potentially blocking operation.
end B_Type;

type A_Type is limited record
B : B_Type;
end record;

end P;

Then, implementation of methods on A_Type will then simply pass
control to the corresponding ones of its B component. All of this,
just to hide something which is not to be part of the public
specification.

I don't like it, because it does not any more publicly shows that
things relies on a protected object.

Was this a desired consequence when this part of Ada was designed ?

Do someone know a reason ?

Is there something I'm doing here I should not do ?

Martin

non lue,
8 févr. 2010, 03:30:1208/02/2010
à
On Feb 8, 4:30 am, Hibou57 (Yannick Duchêne)

This is true of task types too.

We take the view that if something was a task/protected or not should
be hidden from a user (e.g. we may change the behaviour from being
task based/not protected, so we abstract away that information). The
associated 'rule' for callers is that they can't assume that calls to
any operation don't block - but that's true of calling pretty much any
package anyway.

I wonder if there is room for "pragma (Not_)Blocking"?...Not just as a
visual aid but maybe it could also be used extend the usage of "pragma
Detect_Blocking" to wrappers for "foreign languages".

Cheers
-- Martin

Hibou57 (Yannick Duchêne)

non lue,
8 févr. 2010, 04:11:1308/02/2010
à
On 8 fév, 09:30, Martin <martin.do...@btopenworld.com> wrote:
> This is true of task types too.
Indeed

> We take the view that if something was a task/protected or not should
> be hidden from a user (e.g. we may change the behaviour from being
> task based/not protected, so we abstract away that information).

Your suggestion seems to confirm a feeling I was expressing in a
previous thread :
http://groups.google.com/group/comp.lang.ada/browse_thread/thread/385c146dd3112519?hl=fr#
(sorry for pure Usenet user, it's a google-newsgroup link)

> [...]
> Any way, a request made to a task is blocking as long as the task is
> not ready to fulfill the request (the rendezvous, which is the Ada
> primitive for synchronization). So, from the client point of view, a
> method implemented on top of a task is not a different thing than a
> method implemented on top of a procedure.
> [...]


> The associated 'rule' for callers is that they can't assume that calls to
> any operation don't block - but that's true of calling pretty much any
> package anyway.

On one hand, an implementation level detail
On the other hand, something which I feel should be part of the
interface.
I would like to underline : “ part of the interface ”, because while I
was writing these four words, I though “ part of the interface... but
what about the specification ? ”

Most of time I use the words Interface and Specification as
equivalent, but there, I see it's not the same. Blocking, is unlikely
to be part of any required specification. In the mean time, None-
Blocking, is most likely to be a specification requirement.

So : implementation detail or mediumly part of specifications ?

> I wonder if there is room for "pragma (Not_)Blocking"?...Not just as a
> visual aid but maybe it could also be used extend the usage of "pragma
> Detect_Blocking" to wrappers for "foreign languages".

This sounds good to me in someway (I mean providing the latter
question can be answered), as I was also on my side, thinking about a
similar thing : should or should not, Ada, have a keyword or a pragma
to tell a particular method is potentially blocking ?

In the other thread I've pointed, someone suggested me tasks as record
components is most of time not a good idea. But as the only way to
hide private features, is to wrap the target item in a private record
(possibly tagged by the way) type, I wonder what was the reason of
this suggestion to avoid it.

Do you have on you side some feedback to give about experiencing with
task wrapped in private records ? What may be the shortcomings or
traps when using tasks as record components ?

Alex R. Mosteo

non lue,
8 févr. 2010, 05:10:5908/02/2010
à
Hibou57 (Yannick Duchêne) wrote:

I have used tasks as record components in (that I can remember)
communication related types. My rule of thumb is that as long as the type
lifespan is the whole app lifespan, or the type lifespan is derived from the
task lifespan (i.e. end of tasking marks the end of the object, and not the
other way around), things don't present any surprises. With the caveat that
sjw pointed for dynamic deallocation.

I cannot remember any unusual difficulties about it, but I'm only a
practitioner so it's possible I'm also missing some theoretic or obscure
reason to try to avoid it.

Frankly, these non-orthogonalities about regular and protected/tasks types
were really nagging me in Ada95 (the dot notation only for these types, for
instance, and the visibility of privates that you point to). Now at Ada05,
it's the mix of traditional and OO notation caused by interfaces what bugs
me.

Also, the fact that making a protected version of a regular object involves
so much boilerplate code is a regular déjà-vu that pains me in my dreams
(;-)), compare it to java where adding the keyword synchronized is enough.
(Not that I would want java granularity for synchronized; the bugs I've seen
caused by "clever" overoptimization of critical sections...)

Dmitry A. Kazakov

non lue,
8 févr. 2010, 05:20:5208/02/2010
à
On Mon, 8 Feb 2010 00:30:12 -0800 (PST), Martin wrote:

> This is true of task types too.

I don't think so. The task specification does not expose barriers and local
variables of its body. But the protected type specification does its
private operations and components:

package P is
protected type T is
...
private
... -- Why is it here? Is it C++ or Ada?
end T;
private
... -- It belongs here! Or better to the package body
end P;

Obviously to me, the syntax should have been like:

type T is protected private; -- or "protected with private"
entry Foo (X : in out T);
function Bar (X : T) return Boolean;
private
type T is protected record
...
end T; -- I don't like "end record" either.

If you write "limited" instead of "protected", you cannot publicly declare
entries.

(And same for the task types)

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

Hibou57 (Yannick Duchêne)

non lue,
8 févr. 2010, 05:46:2708/02/2010
à
On 8 fév, 11:10, "Alex R. Mosteo" <alejan...@mosteo.com> wrote:
> Frankly, these non-orthogonalities about regular and protected/tasks types
> were really nagging me in Ada95 (the dot notation only for these types, for
> instance, and the visibility of privates that you point to). Now at Ada05,
> it's the mix of traditional and OO notation caused by interfaces what bugs
> me.
Although I've never confessed it here at comp.lang.ada, I feel the
same too, at least about notation. Luckily, Ada still allow me to
preserve consistency granting me the choice to use a dotted notation
or not : I never use the dotted notation for consistency and clarity
purpose (except that it's mandatory with protected types and tasks,
and that's ok for me with record components, as it's implementation
level).

> Also, the fact that making a protected version of a regular object involves
> so much boilerplate code is a regular déjà-vu that pains me in my dreams
> (;-)), compare it to java where adding the keyword synchronized is enough.
> (Not that I would want java granularity for synchronized; the bugs I've seen
> caused by "clever" overoptimization of critical sections...)

I could not tell about comparison between Java and Ada at this point,
as I've never experienced tasking with Java (I use to self-learn Java,
but quickly leave it for some reasons). While the point you've spotted
seems interesting.

Hibou57 (Yannick Duchêne)

non lue,
8 févr. 2010, 05:54:1708/02/2010
à
On 8 fév, 11:20, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> On Mon, 8 Feb 2010 00:30:12 -0800 (PST), Martin wrote:
> > This is true of task types too.
>
> I don't think so. The task specification does not expose barriers and local
> variables of its body. But the protected type specification does its
> private operations and components:
I still think so :p
What about a task entry which should be accessible by some entities of
the package implementation ? I'm not talking about these task's
private entries intended for Requeue, I'm talking about an entry which
should be publicly available while still being available, not only
from the task itself, and also from the package body which hold the
task implementation.

> Obviously to me, the syntax should have been like:
>
>    type T is protected private; -- or "protected with private"
>    entry Foo (X : in out T);
>    function Bar (X : T) return Boolean;
> private
>    type T is protected record
>       ...

So, with absolute majority, the Gang Of Three voted there is a flaw
here

Yes, I would have enjoyed too a "protected [with] private".

>    end T;  -- I don't like "end record" either.

This makes me remind I will have to later reply to another thread
where you also talking about some other stuff you don't like

Hibou57 (Yannick Duchêne)

non lue,
8 févr. 2010, 05:58:3508/02/2010
à
Tipo error : “ I'm talking about an entry which should *not* be
publicly available ” instead of “ I'm talking about an entry which
should be publicly available ”

Dmitry A. Kazakov

non lue,
8 févr. 2010, 06:01:3208/02/2010
à
On Mon, 8 Feb 2010 02:54:17 -0800 (PST), Hibou57 (Yannick Duch�ne) wrote:

> On 8 f�v, 11:20, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>


> wrote:
>> On Mon, 8 Feb 2010 00:30:12 -0800 (PST), Martin wrote:
>>> This is true of task types too.
>>
>> I don't think so. The task specification does not expose barriers and local
>> variables of its body. But the protected type specification does its
>> private operations and components:

> I still think so :p
> What about a task entry which should be accessible by some entities of
> the package implementation ? I'm not talking about these task's
> private entries intended for Requeue, I'm talking about an entry which
> should be publicly available while still being available, not only
> from the task itself, and also from the package body which hold the
> task implementation.

Yes, OK. Maybe it is not so offending as private components of a protected
type, but you are right. "C++-ish" notation (wasn't it actually before
C++?) poison is at work here as well.

Georg Bauhaus

non lue,
8 févr. 2010, 08:19:2408/02/2010
à
Dmitry A. Kazakov schrieb:

Perhaps a combination of Eiffel's visibility sets and
Ada's seperation of spec and body?

Robert A Duff

non lue,
8 févr. 2010, 09:56:4208/02/2010
à
"Hibou57 (Yannick Duch�ne)" <yannick...@yahoo.fr> writes:

> So, with absolute majority, the Gang Of Three voted there is a flaw
> here

Make that four. ;-)

Private parts are a kludge in the first place, and the way
they work with public protected types is even worse, as
you pointed out.

However, I think you can get the hiding you want by using
a protected or synchronized interface.

- Bob

Robert A Duff

non lue,
8 févr. 2010, 10:17:1608/02/2010
à
"Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> writes:

> Yes, OK. Maybe it is not so offending as private components of a protected
> type, but you are right. "C++-ish" notation (wasn't it actually before
> C++?) poison is at work here as well.

According to this:

http://research.scee.net/files/presentations/gcapaustralia09/Pitfalls_of_Object_Oriented_Programming_GCAP_09.pdf

C++ development started in 1979, and was named "C++" in 1983.
Ada development started in the late 70's (not sure exactly,
probably before 1979), and was named "Ada" before 1983.
So I think Ada slightly predates C++.

It also says C++ was standardized in 1998. Is that right?
I'm surprised it was so late...
Ada was first standardized in 1983.

IIRC, Ada 83 tasks did not have private parts, and protected types
did not exist. Packages had private parts. They were a mistake,
IMHO. But I don't think it's fair to blame Bjarne Stroustrup for
this mistake. ;-)

- Bob

Dmitry A. Kazakov

non lue,
8 févr. 2010, 10:36:2308/02/2010
à
On Mon, 08 Feb 2010 09:56:42 -0500, Robert A Duff wrote:

> However, I think you can get the hiding you want by using
> a protected or synchronized interface.

Right, it is better now with Ada 2005.

Nevertheless it is not too late to add the "standard" Ada syntax for task
and protected types declarations leaving the old one supported for
compatibility reasons. I mean

type T is task { private | record ... };
type S is protected { private | record ... };

Robert A Duff

non lue,
8 févr. 2010, 11:06:2708/02/2010
à
"Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> writes:

> On Mon, 08 Feb 2010 09:56:42 -0500, Robert A Duff wrote:
>
>> However, I think you can get the hiding you want by using
>> a protected or synchronized interface.
>
> Right, it is better now with Ada 2005.
>
> Nevertheless it is not too late to add the "standard" Ada syntax for task
> and protected types declarations leaving the old one supported for
> compatibility reasons. I mean
>
> type T is task { private | record ... };
> type S is protected { private | record ... };

What were they thinking?! The "task type T is..." syntax
is so obviously broken. The protected syntax just copied
that mistake, so it's not a mistake by itself.

Unfortunately, we can't simplify the language by replacing
the old syntax -- as you say, it's needed for compatibility.

- Bob

(see below)

non lue,
8 févr. 2010, 11:15:1108/02/2010
à
On 08/02/2010 15:17, in article wccr5ov...@shell01.TheWorld.com,
"Robert A Duff" <bob...@shell01.TheWorld.com> wrote:

...

> IIRC, Ada 83 tasks did not have private parts, and protected types
> did not exist. Packages had private parts. They were a mistake,
> IMHO. But I don't think it's fair to blame Bjarne Stroustrup for
> this mistake. ;-)

I guess we have to blame Jean Ichbiah? 8-)

Strangely, LIS, his ancestor of Ada, did not do this but had distinct,
separately compiled, interface, representation, and algorithm parts for the
LIS equivalent of packages.

I wonder what the rationale was for merging the first two. I suspect
compiler efficiency worries, valid at the time, that now are obsolete.

--
Bill Findlay
<surname><forename> chez blueyonder.co.uk


Jeffrey R. Carter

non lue,
8 févr. 2010, 12:11:5508/02/2010
à
Robert A Duff wrote:
>
> C++ development started in 1979, and was named "C++" in 1983.
> Ada development started in the late 70's (not sure exactly,
> probably before 1979), and was named "Ada" before 1983.
> So I think Ada slightly predates C++.

"Green is Ada" occurred in 1980.

> It also says C++ was standardized in 1998. Is that right?
> I'm surprised it was so late...
> Ada was first standardized in 1983.

In 1980 (MIL-STD-1815, Ada 80).

Ada will be 30 on 2010 Dec 10 (the 195th anniversary of the birth of Augusta Ada
King, Countess of Lovelace, nee Byron).

--
Jeff Carter
"All citizens will be required to change their underwear
every half hour. Underwear will be worn on the outside,
so we can check."
Bananas
29

Jean-Pierre Rosen

non lue,
8 févr. 2010, 12:46:0608/02/2010
à
Robert A Duff a �crit :

> "Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> writes:

> What were they thinking?! The "task type T is..." syntax
> is so obviously broken. The protected syntax just copied
> that mistake, so it's not a mistake by itself.
>

That it is nice to have singletons that are clearly singletons, with a
syntax close to the syntax for types.

--
---------------------------------------------------------
J-P. Rosen (ro...@adalog.fr)
Visit Adalog's web site at http://www.adalog.fr

Robert A Duff

non lue,
8 févr. 2010, 15:39:1908/02/2010
à
Jean-Pierre Rosen <ro...@adalog.fr> writes:

> Robert A Duff a �crit :
>> "Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> writes:
>
>> What were they thinking?! The "task type T is..." syntax
>> is so obviously broken. The protected syntax just copied
>> that mistake, so it's not a mistake by itself.
>>
> That it is nice to have singletons that are clearly singletons, with a
> syntax close to the syntax for types.

Why on earth would you want an object decl to look like
a type decl?

The syntax for a variable decl is:

X : T;

If we want to use an anonymous array type, we say:

X : array (...) of ...; -- unclearly a singleton? Hmm...

So clearly the syntax for singleton tasks should be:

My_Task : task ... -- seems clear to me

rather than:

task My_Task is ...

And why are singletons allowed for some types but not others?
If they make sense for arrays, tasks, and protected objects,
then they make sense for records, etc.

Sorry, but I stand by my opinion that this area is a mess!
It's not hugely important, though.
I guess I just value uniformity more than JDI.

Note that syntactic uniformity makes the RM smaller, partly because
of fewer syntax rules, but more importantly because
non-syntax rules need to refer to syntactic categories by name.

- Bob

Robert A Duff

non lue,
8 févr. 2010, 15:44:0508/02/2010
à
"(see below)" <yald...@blueyonder.co.uk> writes:

> Strangely, LIS, his ancestor of Ada, did not do this but had distinct,
> separately compiled, interface, representation, and algorithm parts for the
> LIS equivalent of packages.

Interesting. I don't know anything about LIS.

> I wonder what the rationale was for merging the first two. I suspect
> compiler efficiency worries, valid at the time, that now are obsolete.

I wonder, too. I don't buy the "compiler efficiency" worries.
That might explain why private parts exist, but it doesn't
explain why they can't be separately compiled (i.e. stored
in separate source files).

I'd eliminate them altogether, though.

- Bob

Hibou57 (Yannick Duchêne)

non lue,
8 févr. 2010, 16:50:1508/02/2010
à
On 8 fév, 18:46, Jean-Pierre Rosen <ro...@adalog.fr> wrote:
> That it is nice to have singletons that are clearly singletons, with a
> syntax close to the syntax for types.

I agree with you about the singleton we can have with Protected
Name .... End Name;
But this is not the actual spot, which is Task type and Protected type
are declared (not singleton).

Hibou57 (Yannick Duchêne)

non lue,
8 févr. 2010, 16:54:3608/02/2010
à
On 8 fév, 21:39, Robert A Duff <bobd...@shell01.TheWorld.com> wrote:

> Jean-Pierre Rosen <ro...@adalog.fr> writes:
> > That it is nice to have singletons that are clearly singletons, with a
> > syntax close to the syntax for types.
>
> Why on earth would you want an object decl to look like
> a type decl?
You may want to have a protected singleton or task singleton, the same
way you may want an entity to be aliased or constant.

You do Aliased or Constant on selective entities, you can do Protected
or Task on selective entities the same way.

By the way, although this construct may seems strange to one who never
use it (I use it, at least, I'm experiencing with it, so it does not
seems strange to me), no troubles at all comes with it. This
particular construct does not brake any language design principle.

Hibou57 (Yannick Duchêne)

non lue,
8 févr. 2010, 17:00:5308/02/2010
à
On 8 fév, 21:44, Robert A Duff <bobd...@shell01.TheWorld.com> wrote:

> "(see below)" <yaldni...@blueyonder.co.uk> writes:
> > I wonder what the rationale was for merging the first two. I suspect
> > compiler efficiency worries, valid at the time, that now are obsolete.
>
> I wonder, too.  I don't buy the "compiler efficiency" worries.
> That might explain why private parts exist, but it doesn't
> explain why they can't be separately compiled (i.e. stored
> in separate source files).
This point is funny, because before I knew enough on Ada (and before I
started to experiment its tasking capabilities), I use to think tasks
was probably separate compilation units (I've understood it was not
when I've checked the syntax rules about it).

If it would have been, then this would also have seems intuitive.
But there again, this does not really break anything (IMHO)

Hibou57 (Yannick Duchêne)

non lue,
8 févr. 2010, 17:04:4008/02/2010
à
On 8 fév, 15:56, Robert A Duff <bobd...@shell01.TheWorld.com> wrote:

> "Hibou57 (Yannick Duchêne)" <yannick_duch...@yahoo.fr> writes:
>
> > So, with absolute majority, the Gang Of Three voted there is a flaw
> > here
>
> Make that four.  ;-)
Robert, ... you forget to give it a Capital Letter ;)

Randy Brukardt

non lue,
8 févr. 2010, 19:48:3908/02/2010
à
"Dmitry A. Kazakov" <mai...@dmitry-kazakov.de> wrote in message
news:1v2la97s2yyvd.1...@40tude.net...

> On Mon, 8 Feb 2010 00:30:12 -0800 (PST), Martin wrote:
>
>> This is true of task types too.
>
> I don't think so. The task specification does not expose barriers and
> local
> variables of its body. But the protected type specification does its
> private operations and components:
>
> package P is
> protected type T is
> ...
> private
> ... -- Why is it here? Is it C++ or Ada?
> end T;
> private
> ... -- It belongs here! Or better to the package body
> end P;
>
> Obviously to me, the syntax should have been like:

For what it's worth, the Ada 95 Rationale says
(http://www.adaic.com/standards/95rat/RAThtml/rat95-p2-9.html#1):

The other data components of a protected object must be declared in the
specification of the type to ensure that the size is known to the compiler
when the type is used by a caller. However these components are only
accessible from protected operations defined in the body of the protected
type and thus are declared in the private part of the protected type.
(And I have no intent of trying to defend this!)

Randy.


AdaMagica

non lue,
9 févr. 2010, 00:48:3309/02/2010
à
> I wonder, too.  I don't buy the "compiler efficiency" worries.
> That might explain why private parts exist, but it doesn't
> explain why they can't be separately compiled (i.e. stored
> in separate source files).
>
> I'd eliminate them altogether, though.

OK, but then you have a similar problem to Ada83's syntactically
unneeded bodies which Ada95 solved with a pragma.

How would you specify that there is a syntactically unneeded private
part (i.e. when there is no private type in the spec)?

I guess your ideas about specs, bodies, child packages and visibility
are very different from Ada as she is. You'd like a different girl,
wouldn't you;-)

stefan...@see-the.signature

non lue,
9 févr. 2010, 04:04:4509/02/2010
à
On Mon, 8 Feb 2010, Robert A Duff wrote:

> "(see below)" <yald...@blueyonder.co.uk> writes:
>
> > Strangely, LIS, his ancestor of Ada, did not do this but had distinct,
> > separately compiled, interface, representation, and algorithm parts for the
> > LIS equivalent of packages.

I am still waiting for an Ada 20XY amandmend, which allows something like

package Blah; is

...

private
is separate; -- you might find it in blah.separate.ads --

end Blah;


--
------ Stefan Lucks -- Bauhaus-University Weimar -- Germany ------
Stefan dot Lucks at uni minus weimar dot de
------ I love the taste of Cryptanalysis in the morning! ------

Hibou57 (Yannick Duchêne)

non lue,
9 févr. 2010, 05:58:5309/02/2010
à
On 8 fév, 15:56, Robert A Duff <bobd...@shell01.TheWorld.com> wrote:
> "Hibou57 (Yannick Duchêne)" <yannick_duch...@yahoo.fr> writes:
> Private parts are a kludge in the first place, and the way
> they work with public protected types is even worse, as
> you pointed out.
>
> However, I think you can get the hiding you want by using
> a protected or synchronized interface.
>

protected, task and synchronized interface seems nice at first sight.
All three because they states what things are, while hiding
implementation details.
The third one especially, because the Synchronized tray in clean-
abstract (as the Ada 95 rationale says on purpose, there is mostly no
difference, from a client point of view, between a protected type and
a task type).

But these interfaces type are too much restrictive. As an example, it
does not allow to define a type which could be automatically allocated
in a local scope. It impose a design where the client must rely on
access to class-wide. This may be nice... but only it was decided to
be so. If something else was to be done, we face a no choice-path.

A direct consequence is also that it requires to use and manage
dynamic allocation in a none-clean way, as the client must make direct
use of an access type. If multiple types are to be defined with same
consequences for each, things become not clean at all.

I feel (at least from my point of view), the most practicable manner
is still to define a private type with primitives, and wrap things
inside that private type in the private part (so there may be no
better design than the initially introduced one).

Hibou57 (Yannick Duchêne)

non lue,
9 févr. 2010, 07:43:3909/02/2010
à
On 8 fév, 11:20, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de>
wrote:

> package P is
>    protected type T is
>       ...
>    private
>       ... -- Why is it here? Is it C++ or Ada?
>    end T;
> private
>    ... -- It belongs here! Or better to the package body
> end P;
>
About this “ klugde ” (as someone called it), here are some words
which attempt to explain the reason of this syntax :
Quoted from
http://www.adaic.com/standards/95rat/RAThtml/rat95-p2-9.html
(Rationale 95)

> Alternative structures were also considered and rejected. One was
> that the private part of a protected unit be visible to the
> enclosing package. However, this was considered confusing, and felt
> to be inconsistent with the visibility of the private part of a
> subpackage. We also considered splitting the protected type (and
> task) specification into two separate parts, with the private
> operations and data components declared in a second part included
> inside the private part of the enclosing package. However, this
> seemed like an unnecessary extra syntactic complexity, so we finally
> adopted the simpler suggestion from two Revision Requests (RR-0487,
> RR-0628) of using private within the specification to demarcate the
> private operations.

Robert A Duff

non lue,
9 févr. 2010, 09:47:1609/02/2010
à
"Hibou57 (Yannick Duch�ne)" <yannick...@yahoo.fr> writes:

> But these interfaces type are too much restrictive. As an example, it
> does not allow to define a type which could be automatically allocated
> in a local scope.

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?

- Bob

Robert A Duff

non lue,
9 févr. 2010, 09:56:0709/02/2010
à
AdaMagica <christo...@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.

> How would you specify that there is a syntactically unneeded private
> part (i.e. when there is no private type in the spec)?

Same way. And as I said, my preference would be to eliminate
private parts altogether.

> I guess your ideas about specs, bodies, child packages and visibility
> are very different from Ada as she is. You'd like a different girl,
> wouldn't you;-)

Girl? Heh.

Ada is my favorite programming language (of the ones that exist
in the real world). The changes I've suggested are minor
improvements. So no, not "very different".

And of course it's all fantasy -- I'm not seriously suggesting
Ada should be changed in incompatible ways!

- Bob

Alex R. Mosteo

non lue,
9 févr. 2010, 09:55:2009/02/2010
à
Hibou57 (Yannick Duchêne) wrote:

My Java is fairly rusty, but if I'm not mistaken, the thing is like this
(corrections welcome!):

(A)
public class Blah { ... } // A regular class

public synchronized class Blah {} // All subprograms of Blah are now
thread-safe.

However, you can also:

(B)
public class Blah
{
public synchronized get() {}
public synchronized set() {}
public bang() {}

}

So basically you choose which methods are synchronized. Or, even further:

(C)
public class Blah
{
public void set() {
synchronized(this) {
// Using this as the lock, operate exclusively within this block.
}
}
}

In my (limited) observing experience, programmers with a tendency to
premature optimization (we all start like that, I fear) avoid (A) because
it's seen as too restrictive. (I don't actually know if Java has a read-only
lock and write lock model like Ada, or using (A) makes all subprograms
mutually exclusive).

So they tend to rely on (B) or (C). At that point, it's really too easy to
somewhere, sometime, forget about a necessary lock, and funny heisenbugs
start to happen caused by obscure race conditions.

I really love the tasking+protected model of Ada.

Hibou57 (Yannick Duchêne)

non lue,
9 févr. 2010, 14:34:2809/02/2010
à
On 9 fév, 15:47, Robert A Duff <bobd...@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?
>
> - Bob

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.

Hibou57 (Yannick Duchêne)

non lue,
9 févr. 2010, 15:19:5709/02/2010
à
On 9 fév, 20:34, Hibou57 (Yannick Duchêne) <yannick_duch...@yahoo.fr>
wrote:

> 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 forget to underline : an extension aggregate which would have
otherwise make it possible to initialize a limited class wide type in
an extended return statement, does not work here, as we are to create
a task or protected object (I do not know such a thing as extension
aggregates for Protected and Task).

Robert A Duff

non lue,
9 févr. 2010, 18:29:5609/02/2010
à
"Hibou57 (Yannick Duch�ne)" <yannick...@yahoo.fr> writes:

> 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 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

Randy Brukardt

non lue,
9 févr. 2010, 21:29:5909/02/2010
à
"Robert A Duff" <bob...@shell01.TheWorld.com> wrote in message
news:wccy6j2...@shell01.TheWorld.com...

> AdaMagica <christo...@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.

I think you're forgetting how this happens in practice. And the actual
problem with Ada 83, which was that a unneeded unit with an error had to be
ignored when linking. (The ACVC used to insist on that.) Ada surely needed a
fix to that problem, and it wasn't one with the implementations -- at least
not until they were changed to match the ACVC. (I remember doing that in
Janus/Ada, it was a lot of work and it made things worse for users.
Wonderful.)

Moreover, it is easy to imagine errors that would cause the unit to no
longer be the body (such as misspelling the name, or misspelling "body"), at
which point the implementation would have to guess. But the problem of a
body that the programmer expected to be included being left out would
continue. So while I don't doubt that implementations could have reduced the
problem (in the absense of the ACVC test - the main thing I wanted from Ada
95 was to change the rules enough to repeal that stupid test!), they
couldn't have fixed it completely. Surely the same dynamic would occur for a
separate private part.

I'm also dubious of the basic idea. I suppose you could keep the private
part in a separate file, but I can't imagine any useful way to *compile* it
separately (you'd have to have both parts available in order to do any sort
of code generation). So there wouldn't be much, if any, advantage in terms
of development. (For Janus/Ada, at least, every source file is compiled
separately, and code is generated as necessary without needing anything
other than direct semantic dependencies to have been previously compiled.
That model is impossible for separate private parts; the specification would
not contain enough information to generate any code or any code for calls to
it.)

Randy.


Randy Brukardt

non lue,
9 févr. 2010, 21:39:4109/02/2010
à
"Hibou57 (Yannick Duch�ne)" <yannick...@yahoo.fr> wrote in message
news:4e959c35-34d1-49fb...@z19g2000yqk.googlegroups.com...

>On 9 f�v, 15:47, Robert A Duff <bobd...@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.


Hibou57 (Yannick Duchêne)

non lue,
10 févr. 2010, 00:12:0410/02/2010
à

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.

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...@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.

Hibou57 (Yannick Duchêne)

non lue,
10 févr. 2010, 02:17:5310/02/2010
à
On 10 fév, 06:12, Hibou57 (Yannick Duchêne) <yannick_duch...@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

Adam Beneschan

non lue,
10 févr. 2010, 11:05:5910/02/2010
à
On Feb 9, 6:56 am, Robert A Duff <bobd...@shell01.TheWorld.com> wrote:

> AdaMagica <christoph.gr...@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

Robert A Duff

non lue,
10 févr. 2010, 11:09:3910/02/2010
à
"Hibou57 (Yannick Duch�ne)" <yannick...@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

sjw

non lue,
10 févr. 2010, 15:17:1410/02/2010
à
On Feb 10, 4:05 pm, Adam Beneschan <a...@irvine.com> wrote:

>  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.

"that issue *would* exist with GNAT also", I think.

Hibou57 (Yannick Duchêne)

non lue,
10 févr. 2010, 17:21:0110/02/2010
à
On 10 fév, 17:09, Robert A Duff <bobd...@shell01.TheWorld.com> wrote:
> > 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.
Ok, I was thinking your way of writing thing was not so silly, but as
there was the ARM...

My GNAT is GPL 2009 (20090519). I had a look to see if there is an
update, but I did not find one (on AdaCore website, its still saying
GPL 2009).

Do you have a reference for this Ada Issue ? Which number ?

About the crash while compiling, I've found a workaround which "solve"
it in an acceptable manner, I will open a thread later or tomorrow to
tell about it.

At the time, I'm facing another trouble, which seems as much strange.
Not a crash, but I wonder if either GNAT is wrong of if I did not
understood the RM about 9.7.2(3.2/2) and controlling parameters (

Robert A Duff

non lue,
10 févr. 2010, 19:48:1910/02/2010
à
"Hibou57 (Yannick Duch�ne)" <yannick...@yahoo.fr> writes:

> My GNAT is GPL 2009 (20090519). I had a look to see if there is an
> update, but I did not find one (on AdaCore website, its still saying
> GPL 2009).

I don't keep track of what public versions of GNAT are out there,
or which fixes are in them, so I can't help you on that.

> Do you have a reference for this Ada Issue ? Which number ?

AI05-0032-1. There's another AI on this same paragraph,
AI05-0103-1, but I don't think it's relevant to this discussion.

> About the crash while compiling, I've found a workaround which "solve"
> it in an acceptable manner, I will open a thread later or tomorrow to
> tell about it.

If GNAT crashes, you should report the bug to AdaCore. AdaCore
accepts bug reports from the public, and eventually fixes them,
but of course at lower priority than bugs reported by paying
customers.

> At the time, I'm facing another trouble, which seems as much strange.
> Not a crash, but I wonder if either GNAT is wrong of if I did not
> understood the RM about 9.7.2(3.2/2) and controlling parameters (

Something missing here?

- Bob

Robert A Duff

non lue,
11 févr. 2010, 18:46:2311/02/2010
à
"Randy Brukardt" <ra...@rrsoftware.com> writes:

> "Robert A Duff" <bob...@shell01.TheWorld.com> wrote in message
> news:wccy6j2...@shell01.TheWorld.com...
>> AdaMagica <christo...@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.
>
> I think you're forgetting how this happens in practice. And the actual
> problem with Ada 83, which was that a unneeded unit with an error had to be
> ignored when linking.

Well, that's what the Ada 83 RM seemed to require. I thought so
at the time. But later I realized that the RM could be interpreted
to mean something different -- after all, it doesn't actually
talk about "linking".

>...(The ACVC used to insist on that.)

Yeah. The implementers should have fought against that,
rather than damaging their compilers.

Or, they could at least have given warnings, which is good
enough to solve the problem.

Or fix the problem in the "build" command (I mean gnatmake
or whatever).

>... Ada surely needed a

> fix to that problem, and it wasn't one with the implementations -- at least
> not until they were changed to match the ACVC. (I remember doing that in
> Janus/Ada, it was a lot of work and it made things worse for users.
> Wonderful.)
>
> Moreover, it is easy to imagine errors that would cause the unit to no
> longer be the body (such as misspelling the name, or misspelling "body"), at

I see your point about misspelling the name. But misspelling "body"?
That would just be a syntax error.

> which point the implementation would have to guess. But the problem of a
> body that the programmer expected to be included being left out would
> continue.

But the so-called "solution" in Ada 95 didn't actually solve anything.
Early versions of GNAT had the same bug -- they ignored a non-required
body, simply by saying it's not part of the program library.
That was fixed because it's bad behavior, not because it failed
to conform to the Ada 95 rules.

>...So while I don't doubt that implementations could have reduced the

> problem (in the absense of the ACVC test - the main thing I wanted from Ada
> 95 was to change the rules enough to repeal that stupid test!), they
> couldn't have fixed it completely. Surely the same dynamic would occur for a
> separate private part.
>
> I'm also dubious of the basic idea. I suppose you could keep the private
> part in a separate file, but I can't imagine any useful way to *compile* it
> separately (you'd have to have both parts available in order to do any sort
> of code generation).

I don't think you need to look at the private part to generate code.
If you change it to "to generate efficient code", then I'll agree.

>...So there wouldn't be much, if any, advantage in terms
> of development.

I disagree -- I think there are big advantages to storing the
private part in a separate file. I don't much care what files
the compiler wants to look at, so long as it's not too slow.

The private part is part of the implementation. It's useful
to manage it separately in your CM system (and CM systems
are file based). Consider, for example, a visible part
that has multiple implementations (maybe target dependent),
selected by the build scripts. It's really annoying to
have to duplicate the visible part.

>... (For Janus/Ada, at least, every source file is compiled

> separately, and code is generated as necessary without needing anything
> other than direct semantic dependencies to have been previously compiled.
> That model is impossible for separate private parts; the specification would
> not contain enough information to generate any code or any code for calls to
> it.)

This seems backwards. Of course you chose a compilation model
based on the rules of Ada (Ada 83, in fact). But I'm speculating
about what Ada should have been -- a language very similar
to Ada, but slightly different. You can't argue against such
a language by saying existing Ada compilers can't handle it.
If Ada had been designed differently, then so would the compilers
have been.

Ada allows recursion. Therefore, an Ada implementation must
use a stack. I can't say, "I want to statically allocate
all variables at link-time-known addresses." Sorry, that's
just a wrong implementation of Ada. It's not a valid argument
against allowing recursion.

- Bob

Robert A Duff

non lue,
11 févr. 2010, 18:53:5011/02/2010
à
"Randy Brukardt" <ra...@rrsoftware.com> writes:

>...(For Janus/Ada, at least, every source file is compiled

> separately, and code is generated as necessary without needing anything
> other than direct semantic dependencies to have been previously compiled.
> That model is impossible for separate private parts; the specification would
> not contain enough information to generate any code or any code for calls to
> it.)

The Ada 83 model seemed to be that the compiler doesn't need to look at
with'ed bodies to generate code. But that's bogus. All Ada compilers
other than Janus/Ada look at bodies to generate code for generic
instantiations. And you need to look at bodies to implement
inlining properly. (Does Janus/Ada implement inlining?)
Similarly for any other inter-package optimizations.

Given that compilers do, in fact, look at bodies of with'ed packages,
they could use the same mechanism for separate private parts.
Or, if private parts didn't exist, to look at bodies to find
the completion of private types, for example.

- Bob

Robert A Duff

non lue,
11 févr. 2010, 19:05:0011/02/2010
à
Adam Beneschan <ad...@irvine.com> writes:

> On Feb 9, 6:56�am, Robert A Duff <bobd...@shell01.TheWorld.com> wrote:
>> AdaMagica <christoph.gr...@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. :) :)

Sure. I don't see a problem with that. (It's not really "every file on
the disk" of course -- it's "every file with so-and-so extension in the
directories where the compiler was told to look".) AdaMagic, for
example, does this. The trick to making it efficient is to cache
the information in a UNIT.MAP file.

> 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.

Not 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.

I suppose so, but I think that problem could be solved by a good
build system, too. It could complain about stray bodies lying
around the place with (misspelled) names that don't match any
spec.

>...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.

Seems unlikely.

Here's a similar issue: One reasonable design pattern is to have
a body that contains a type extension, which registers itself
into some global data structure. All calls to this thing
are indirect (via the parent's 'Class). Nobody needs visibility
on this thing, so its spec is completely empty, except for
the obligatory pragma Elaborate_Body. Unfortunately, if you
forget to 'with' it, it will be silently ignored.

- Bob

Randy Brukardt

non lue,
11 févr. 2010, 20:10:4911/02/2010
à
"Robert A Duff" <bob...@shell01.TheWorld.com> wrote in message
news:wccr5or...@shell01.TheWorld.com...

> "Randy Brukardt" <ra...@rrsoftware.com> writes:
>
>>...(For Janus/Ada, at least, every source file is compiled
>> separately, and code is generated as necessary without needing anything
>> other than direct semantic dependencies to have been previously compiled.
>> That model is impossible for separate private parts; the specification
>> would
>> not contain enough information to generate any code or any code for calls
>> to
>> it.)
>
> The Ada 83 model seemed to be that the compiler doesn't need to look at
> with'ed bodies to generate code. But that's bogus.

It's not bogus, the existence of Janus/Ada demonstrates that. And other Ada
83 compilers worked that way as well.

> All Ada compilers
> other than Janus/Ada look at bodies to generate code for generic
> instantiations. And you need to look at bodies to implement
> inlining properly. (Does Janus/Ada implement inlining?)
> Similarly for any other inter-package optimizations.

I don't believe in inlining(*). Nor inter-package optimizations in typical
compilation modes. Our model is that the only dependencies are the actual
semantic dependencies caused by with clauses (and stubs, which work much
like with clauses). Everything was designed to have tolerable compilation
speeds on original PCs, and no program library at all (just a pile of files
somewhere). Obviously, those choices aren't as important these days, I
wouldn't design it the same if I was starting today.

(*) I think inlining is something that should be done automatically by the
compiler. I see no reason at all to clutter source code with hints that the
compiler could figure out better on its own. It would be much better if the
source was annotated with the intended time/space tradeoffs: make this loop
as fast as possible, make this rarely used subsystem as small as possible,
make everything else "normal". This is one advantage that just-in-time
compilation has: it actually has data to suggest what is important.

I also believe that the only reasonable compilation model in the limit is of
full program compilation - if I started a compiler design today I would
build it around that model where most of the work is done at what today is
called "link-time". (Or even just-in-time.) So if we're talking hypothetical
languages, compilation would also be very different. But this is an Ada
forum, and I'm not much interested in hypotheticals.

Randy.


Randy Brukardt

non lue,
11 févr. 2010, 20:29:4811/02/2010
à
"Robert A Duff" <bob...@shell01.TheWorld.com> wrote in message
news:wccvde3...@shell01.TheWorld.com...
> "Randy Brukardt" <ra...@rrsoftware.com> writes:
...

>> Moreover, it is easy to imagine errors that would cause the unit to no
>> longer be the body (such as misspelling the name, or misspelling "body"),
>> at
>
> I see your point about misspelling the name. But misspelling "body"?
> That would just be a syntax error.

I often leave out "body" altogether. But either are a syntax error, but only
if the build system tries to compile the file! And why is it doing that,
build systems don't compile random files that aren't needed.

I could imagine a warning if you have strong links (naming conventions,
whatever) to this particular file, but that is often not the case. (It
wasn't in Janus/Ada until we added the project manager in the mid-90's - if
the file didn't have the right name or the right contents, it was ignored.
We didn't want to be picking up random documents and leftover debugger
files, which used to happen in the old days.)

>> which point the implementation would have to guess. But the problem of a
>> body that the programmer expected to be included being left out would
>> continue.
>
> But the so-called "solution" in Ada 95 didn't actually solve anything.
> Early versions of GNAT had the same bug -- they ignored a non-required
> body, simply by saying it's not part of the program library.
> That was fixed because it's bad behavior, not because it failed
> to conform to the Ada 95 rules.

I don't see how you could "fix" it in general. If the file matches the
naming conventions or already has a link from a project manager, sure you
can see it. But if those things aren't true, are you going to nag the user
everytime? (No body found for package X!) We actually did that for a while
in late Ada 83 days and it drove everybody nuts.

...


>> I'm also dubious of the basic idea. I suppose you could keep the private
>> part in a separate file, but I can't imagine any useful way to *compile*
>> it
>> separately (you'd have to have both parts available in order to do any
>> sort
>> of code generation).
>
> I don't think you need to look at the private part to generate code.
> If you change it to "to generate efficient code", then I'll agree.

I don't know how to compile a subprogram call if I don't know the parameter
passing kind (by-copy or by-reference). You could make everything
by-reference, but then you have to fake by-copy at the call site. Not sure
how you could do that if you don't know anything about the type.

It's the reason you can't make calls to subprograms with parameters of
incomplete types. (We recently discovered that Ada has been wrong about
disallowing the *declaration* of such subprograms; the only problem is
*calling* them; Ada 2012 will relax that restriction, which will be great
for "limited with".)

>>...So there wouldn't be much, if any, advantage in terms
>> of development.
>
> I disagree -- I think there are big advantages to storing the
> private part in a separate file. I don't much care what files
> the compiler wants to look at, so long as it's not too slow.

Maybe. It sounds like more separate windows to juggle in the editor.

> The private part is part of the implementation. It's useful
> to manage it separately in your CM system (and CM systems
> are file based). Consider, for example, a visible part
> that has multiple implementations (maybe target dependent),
> selected by the build scripts. It's really annoying to
> have to duplicate the visible part.

CM systems have been a pet peeve of mind for years. File-based management
simply doesn't work; unfortunately, everything else is too complex to use.
Janus/Ada plenty of files that are mostly shared (like the definition of
Standard for different targets), and it is pain to keep them all consistent.
I built a front-end to our CM system to track those relationships, but it
doesn't work that well because of the need to manually update things, even
when the change is in the shared part (which is the usual case).

There is no particular part of the code that is more or less common for
these "unshared" parts to occur. Bodies, private declarations, and visible
constants all are involved. So you're fixing one corner of a wide tools
problem with a language feature.

If you really wanted to fix that (without creating a new kind of CM
system!), I think you would need to support putting arbitrary parts of
compilation units in different files. Almost like the old include files, but
with first class support in the programming environment so it is easy to see
and work on the assembled result. But that isn't a language enhancement
per-se.

>>... (For Janus/Ada, at least, every source file is compiled
>> separately, and code is generated as necessary without needing anything
>> other than direct semantic dependencies to have been previously compiled.
>> That model is impossible for separate private parts; the specification
>> would
>> not contain enough information to generate any code or any code for calls
>> to
>> it.)
>
> This seems backwards. Of course you chose a compilation model
> based on the rules of Ada (Ada 83, in fact). But I'm speculating
> about what Ada should have been -- a language very similar
> to Ada, but slightly different. You can't argue against such
> a language by saying existing Ada compilers can't handle it.
> If Ada had been designed differently, then so would the compilers
> have been.

We're talking about Ada here (and possibly enhancements to Ada). I'm not
talking about the Duff language, nor am I very interested in it. Ada is
going to be compiled by Ada compilers, and the vast majority of them already
exist. How they work *is* relevant.

Randy.


Stephen Leake

non lue,
12 févr. 2010, 06:07:2812/02/2010
à
Robert A Duff <bob...@shell01.TheWorld.com> writes:

> Adam Beneschan <ad...@irvine.com> writes:
>
>>...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.
>
> Seems unlikely.

Which means it will be very hard/confusing to debug when it does
happen, since you will not be familiar with the problem. So it is
important for the tool to handle the unlikely situations nicely.

> Here's a similar issue: One reasonable design pattern is to have
> a body that contains a type extension, which registers itself
> into some global data structure. All calls to this thing
> are indirect (via the parent's 'Class). Nobody needs visibility
> on this thing, so its spec is completely empty, except for
> the obligatory pragma Elaborate_Body. Unfortunately, if you
> forget to 'with' it, it will be silently ignored.

And if you do 'with' it, GNAT will complain that it's unnecessary, so
you have to put a pragma Warnings (off) on it. QtAda does this for
some stuff; it's annoying.

I prefer to handle that case by making the registration function
visible in the package spec, rather than calling it in the package
body execution part. Then the main program has to call it, and no
compiler warnings are generated.

--
-- Stephe

Robert A Duff

non lue,
12 févr. 2010, 10:01:3712/02/2010
à
Stephen Leake <stephe...@stephe-leake.org> writes:

> Robert A Duff <bob...@shell01.TheWorld.com> writes:
>
>> Adam Beneschan <ad...@irvine.com> writes:
>>
>>>...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.
>>
>> Seems unlikely.
>
> Which means it will be very hard/confusing to debug when it does
> happen, since you will not be familiar with the problem. So it is
> important for the tool to handle the unlikely situations nicely.

I suppose...

>> Here's a similar issue: One reasonable design pattern is to have
>> a body that contains a type extension, which registers itself
>> into some global data structure. All calls to this thing
>> are indirect (via the parent's 'Class). Nobody needs visibility
>> on this thing, so its spec is completely empty, except for
>> the obligatory pragma Elaborate_Body. Unfortunately, if you
>> forget to 'with' it, it will be silently ignored.
>
> And if you do 'with' it, GNAT will complain that it's unnecessary, so
> you have to put a pragma Warnings (off) on it. QtAda does this for
> some stuff; it's annoying.

But that's a hugely useful warning. Without it, you end up with
useless 'with's accumulating in your code. An occassional
pragma Warnings is well worth the trouble, IMHO.

> I prefer to handle that case by making the registration function
> visible in the package spec, rather than calling it in the package
> body execution part. Then the main program has to call it, and no
> compiler warnings are generated.

Self-initializing packages are a Good Thing, I think.

I often do it like this: The parent type is limited controlled,
and Initialize/Finalize install/remove the object into some data
structure. The derived type just overrides some primitive
ops (not Initialize/Finalize), and declares one or more
objects -- all in some package body.

- Bob

Stephen Leake

non lue,
13 févr. 2010, 03:00:1613/02/2010
à

Yes, I agree.

Actually, most of the annoyance is that Emacs Ada mode doesn't
understand about the pragma, so when it automatically adds a new with
clause, and alphabetically sorts the set of with clauses, it messes
things up. So I need to teach Emacs Ada mode how to cope with that
better.

--
-- Stephe

0 nouveau message