comp.lang.ada
 help / color / mirror / Atom feed
* Private primitive operations available to entire package hierarchy. Can it be done?
@ 2005-07-07 16:06 Lucretia
  2005-07-07 16:17 ` OT: Joke Adrien Plisson
  2005-07-07 19:10 ` Private primitive operations available to entire package hierarchy. Can it be done? Randy Brukardt
  0 siblings, 2 replies; 20+ messages in thread
From: Lucretia @ 2005-07-07 16:06 UTC (permalink / raw)


Hi,

In my work with wxAda, I've found a need for some primitives to be
private to the outside of the "wx." package hierarchy, yet packages
within "wx." need to acces them.

e.g.

The package "wx.Window" contains a function which creates an Ada type
rooted at Window_Type for a specific C++ instance type and class name
(i.e. "wxWindow", "wxTopLevelWindow", etc.). This is also required in
other packages, yet I don't want an application using wxAda to be able
to see/use it at all.

I also need to be able to do this without causing cyclic dependencies
as I can see this happening quite easily.

I have also added a factory to allow creation of Ada types from a C++
class name, at the moment, I register each type within the statement
part of a package body. Is there an easier way register these
factories? Currently to register a factory the package needs to be
"with'd".

Thanks,
Luke.

P.S: Has Ada0X been put back another year?




^ permalink raw reply	[flat|nested] 20+ messages in thread

* OT: Joke
  2005-07-07 16:06 Private primitive operations available to entire package hierarchy. Can it be done? Lucretia
@ 2005-07-07 16:17 ` Adrien Plisson
  2005-07-07 16:24   ` Matthew Heaney
  2005-07-07 19:10 ` Private primitive operations available to entire package hierarchy. Can it be done? Randy Brukardt
  1 sibling, 1 reply; 20+ messages in thread
From: Adrien Plisson @ 2005-07-07 16:17 UTC (permalink / raw)


sorry but i just can't resist:

Lucretia wrote:
> P.S: Has Ada0X been put back another year?

yes, it's now Ada0Y...

sorry again.

-- 
rien



^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: OT: Joke
  2005-07-07 16:17 ` OT: Joke Adrien Plisson
@ 2005-07-07 16:24   ` Matthew Heaney
  0 siblings, 0 replies; 20+ messages in thread
From: Matthew Heaney @ 2005-07-07 16:24 UTC (permalink / raw)


WG9 met in York, and the delegates voted to use the name "Ada 2005".
You don't need to bother using a placeholder anymore...




^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Private primitive operations available to entire package hierarchy. Can it be done?
  2005-07-07 16:06 Private primitive operations available to entire package hierarchy. Can it be done? Lucretia
  2005-07-07 16:17 ` OT: Joke Adrien Plisson
@ 2005-07-07 19:10 ` Randy Brukardt
  2005-07-13 15:40   ` Lucretia
  1 sibling, 1 reply; 20+ messages in thread
From: Randy Brukardt @ 2005-07-07 19:10 UTC (permalink / raw)


"Lucretia" <lucretia9@lycos.co.uk> wrote in message
news:1120752411.808598.292980@g49g2000cwa.googlegroups.com...
> Hi,
>
> In my work with wxAda, I've found a need for some primitives to be
> private to the outside of the "wx." package hierarchy, yet packages
> within "wx." need to acces them.
>
> e.g.
>
> The package "wx.Window" contains a function which creates an Ada type
> rooted at Window_Type for a specific C++ instance type and class name
> (i.e. "wxWindow", "wxTopLevelWindow", etc.). This is also required in
> other packages, yet I don't want an application using wxAda to be able
> to see/use it at all.

Put those operations in the private part of the root package of the
hierarchy. All of the child units will be able to see them and override them
if necessary, but programs outside the hierarchy cannot use them. Claw uses
this extensively. Warning: doing this is a sure-fire way to turn up
visibility bugs in Ada compilers.

> I have also added a factory to allow creation of Ada types from a C++
> class name, at the moment, I register each type within the statement
> part of a package body. Is there an easier way register these
> factories? Currently to register a factory the package needs to be
> "with'd".

Generally, I put the registration code in the elaboration part of the
package declaring the type. That means that each package declaring a type
has to "with" the registration package. That's better than the registration
package "with"ing all of the types. (I'm not certain that this structure
actually works with Ada 95, it certainly does with Ada 200Y using the
Generic_Dispatching_Constructor package).

> P.S: Has Ada0X been put back another year?

It looks to be about 6 months late. (Says the editor, who ought to know.)
But we've also taken a more realistic look at the approval schedule for the
standard, and that is likely to stretch well into 2006 and possibly even
2007.

WG9 has decided to continue to call the language "Ada 2005" in the interim.
I personally have reverted to "Ada 200Y", because the year really isn't
known, and I don't see any reason to use a misleading year in the interim.
That is, "Ada 9X" was a better name than "Ada 92" would have been during
development of that standard [yes, Ada 95 was supposed to be approved in
1992 on the original schedule.]. (It's best to use a different name before
and after approval of the standard anyway, so that old outdated material is
not found in web searches and the like.)

                               Randy Brukardt.






^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Private primitive operations available to entire package hierarchy. Can it be done?
  2005-07-07 19:10 ` Private primitive operations available to entire package hierarchy. Can it be done? Randy Brukardt
@ 2005-07-13 15:40   ` Lucretia
  2005-07-19 23:19     ` Randy Brukardt
  0 siblings, 1 reply; 20+ messages in thread
From: Lucretia @ 2005-07-13 15:40 UTC (permalink / raw)


Although the factory that creates an Ada type from a C++ wxWidgets
class name would possibly be ok in the private part of the root package
(wx). Putting all the other primitives I need to be private from
outside of (wx) in the root package isn't possible due to the fact that
the root package (wx) doesn't know about types that those functions may
need (wx.Window.Window_Type). i.e. I have another function which
creates the correct window type from an access type which comes from
the C side of the code, thus it's got an unknown type until it comes
out of this function. This is a problem, and one I have no clue how to
fix.

I'm not too sure I understand what you mean with respect to the
registration packages. I've had to include the factory in wx.Object
package as the registration package has to return a type of
Object_Class and the Object also has to register itself although, I
could possibly change that), thus cyclic dependency!

As for the status of wxAda...I know that a lot of people would like to
use wxWidgets from within Ada, but it's not a trivial task and it's one
I've been working on for at least 6 months (not solidly), maybe more,
I'm not really counting, but:

1) it'll be done when it's done. In other words, once I've got these
problems sorted and I have all the C++ classes wrapped a way that works
and is nice and Ada-like, I'll be posting an announcement to this list.

2) As for the licence, I'd like it to be under the wxWidget licence,
but I'm not sure how compatible that is to the GMGPL (Or whatever it's
called). Basically, I'd like people to be able to use wxAda to create
commercial apps just like they can with wxWidgets without having to
give away the source code as well.

3) I won't be giving away any source before it's finished and hosted
somewhere (whether that's SF, Tigris or if I can get Julian to agree,
wxWidgets, or even my own hosted server, dunno yet) so please don't
ask.

Thanks,
Luke.




^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Private primitive operations available to entire package hierarchy. Can it be done?
  2005-07-13 15:40   ` Lucretia
@ 2005-07-19 23:19     ` Randy Brukardt
  2005-07-20 18:14       ` Lucretia
  0 siblings, 1 reply; 20+ messages in thread
From: Randy Brukardt @ 2005-07-19 23:19 UTC (permalink / raw)


"Lucretia" <lucretia9@lycos.co.uk> wrote in message
news:1121269243.013754.57720@g14g2000cwa.googlegroups.com...
> Although the factory that creates an Ada type from a C++ wxWidgets
> class name would possibly be ok in the private part of the root package
> (wx). Putting all the other primitives I need to be private from
> outside of (wx) in the root package isn't possible due to the fact that
> the root package (wx) doesn't know about types that those functions may
> need (wx.Window.Window_Type). i.e. I have another function which
> creates the correct window type from an access type which comes from
> the C side of the code, thus it's got an unknown type until it comes
> out of this function. This is a problem, and one I have no clue how to
> fix.

These things don't sound very primitive to me. If they don't need to be
dispatching, put them into the private part of the child packages. Another
possibility is to invert the structure, and put them into private child
packages of the root, along with a derived type (not intended to be used
externally). Then derive from that hidden type in a public child. (This also
would seem to require Ada 200Y features, but one that is available in the
newest GNATs). This would look like:

    package Root is
        type Root_Type is tagged ...
        procedure Root_Operation (Obj : in out Root_Operation; ...) is
abstract;
    end Root;

    private package Root.Private_Child is
        type Private_Version_of_Type is new Root_Type with ...
        procedure Private_Operation_1 (Obj : in out Private_Version_of_Type;
...);
        procedure Will_be_Public_Operation (Obj : in out
Private_Version_of_Type; ...);
        procedure Root_Operation (Obj : in out Private_Version_of_Type;
...);
   end Root_Private_Child;

    private with Root.Private_Child; -- Ada 200Y
    package Root.Public_Child is
       type Public_Type is new Root_Type with private;
       procedure Public_Operation (Obj : in out Public_Type; ...);
       -- Root_Operation is inherited, and the version in Private_Child will
be called when it
       -- is referenced or dispatched to. The other two operations are *not*
publically inherited.
    private
       type Public_Type is new Root.Private_Child.Private_Version_of_Type
with ...;
       -- The other two operations are inherited here.
       procedure Public_Operation (Obj : in out Public_Type; ...) renames
Will_be_Public_Operation;
       -- Connect the visible Public_Operation with
Will_be_Public_Operation.
    end Root.Public_Child;

If this doesn't work, then the structure of the system is just too
convoluted. (Which I realize is out of your control.)

> I'm not too sure I understand what you mean with respect to the
> registration packages. I've had to include the factory in wx.Object
> package as the registration package has to return a type of
> Object_Class and the Object also has to register itself although, I
> could possibly change that), thus cyclic dependency!

I don't think it is necessary to register the Object type itself, especially
as it will be abstract in the vast majority of systems. (Thus, there are no
objects.) Even if you do have to, you can special case that and do it at the
point of the registration package (clearly it knows about the type
"Object").

Hope this helps.

                    Randy.






^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Private primitive operations available to entire package hierarchy. Can it be done?
  2005-07-19 23:19     ` Randy Brukardt
@ 2005-07-20 18:14       ` Lucretia
  2005-07-21  3:10         ` Randy Brukardt
  0 siblings, 1 reply; 20+ messages in thread
From: Lucretia @ 2005-07-20 18:14 UTC (permalink / raw)


Yeah thanks. Hmmm, I want to keep the lib Ada95 currently as I really
want the library to be usable with any Ada95 compiler. But if needs
must, then I'll have to shift it to Ada 200Y and screw compatability
for a while.

I'd also like to ask about style from you potential users of wxAda ;-D

I currently have a library where you have instances and these are not
allocated with new (like GtkAda). So, I've found that the use of
aliased is required in a fair few places. I'm wondering whether it
would be better to follow the GtkAda style and allocate the objects
using allocators. What do you lot think?

Also, I use the following:

New_Window(My_Window, ...);
New_Frame(My_Frame, ...);
New_Button(My_Button, ...);
etc.

Would you potential users prefer overloading? a la:

Create(My_Window, ...);
Create(My_Frame, ...);
Create(My_Button, ...);
etc.

Thanks,
Luke.




^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Private primitive operations available to entire package hierarchy. Can it be done?
  2005-07-20 18:14       ` Lucretia
@ 2005-07-21  3:10         ` Randy Brukardt
  2005-07-25 18:14           ` Lucretia
  0 siblings, 1 reply; 20+ messages in thread
From: Randy Brukardt @ 2005-07-21  3:10 UTC (permalink / raw)


"Lucretia" <lucretia9@lycos.co.uk> wrote in message
news:1121883276.400592.326630@o13g2000cwo.googlegroups.com...
...
> I currently have a library where you have instances and these are not
> allocated with new (like GtkAda). So, I've found that the use of
> aliased is required in a fair few places. I'm wondering whether it
> would be better to follow the GtkAda style and allocate the objects
> using allocators. What do you lot think?

My two cents is that the types in question should be tagged (usually because
they're derived from controlled); if that's true, you don't need aliased to
be visible in the user code. (That's how Claw works). That might require a
thicker library than you have in mind, though.

                Randy.







^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Private primitive operations available to entire package hierarchy. Can it be done?
  2005-07-21  3:10         ` Randy Brukardt
@ 2005-07-25 18:14           ` Lucretia
  2005-07-25 23:58             ` Randy Brukardt
  0 siblings, 1 reply; 20+ messages in thread
From: Lucretia @ 2005-07-25 18:14 UTC (permalink / raw)


Erm, they are tagged and in some cases I have needed "aliased" to get
hold of the actual address of the item, i.e. when connecting an event
handler to a frame, you have to give it the address of the event
handler, the lib currently uses this address internally as well.

The lib is already a thick binding:

1) A mirror of the class hierarchy from C++ into Ada tagged types.
2) The primitive operations call imported C functions which in turn
call the necessary C++ methods.
3) Conversions between Ada and C types is done inside the lib and you
never deal with a C.int/long or chars_ptr.

Luke.




^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Private primitive operations available to entire package hierarchy. Can it be done?
  2005-07-25 18:14           ` Lucretia
@ 2005-07-25 23:58             ` Randy Brukardt
  2005-07-27 17:36               ` Lucretia
  0 siblings, 1 reply; 20+ messages in thread
From: Randy Brukardt @ 2005-07-25 23:58 UTC (permalink / raw)


"Lucretia" <lucretia9@lycos.co.uk> wrote in message
news:1122315253.757948.150350@z14g2000cwz.googlegroups.com...
> Erm, they are tagged and in some cases I have needed "aliased" to get
> hold of the actual address of the item, i.e. when connecting an event
> handler to a frame, you have to give it the address of the event
> handler, the lib currently uses this address internally as well.

Tagged parameters are automatically aliased, so you don't need to declare
them explicitly. So it's only necessarily if you're declaring objects
(either stand-alone or components). I'd suggest that that be kept to a
minimum; it's best to let the user code manage the actual objects (which
often will be extensions of some sort). So it should be rare to need to
specify aliased.

In your above description, I'm assuming that the event handler and the frame
are objects passed in to the various routines. In that case, just taking
'Unchecked_Access works fine. If the event handler is some sort of local
object, then of course you'd need aliased. But in this case, this is an Ada
object, but it isn't an "object" in the software engineering sense from
outside of the library. It's not unusual to have to do all sorts of grunge
inside the library, but that's irrelevant. It's not important that *you*
have to declare something aliased; it only matters that you don't force your
users to do so. As long as objects are tagged, that should be the case.

> The lib is already a thick binding:
>
> 1) A mirror of the class hierarchy from C++ into Ada tagged types.
> 2) The primitive operations call imported C functions which in turn
> call the necessary C++ methods.
> 3) Conversions between Ada and C types is done inside the lib and you
> never deal with a C.int/long or chars_ptr.

Sounds good. Good luck with the design.

                                Randy.






^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Private primitive operations available to entire package hierarchy. Can it be done?
  2005-07-25 23:58             ` Randy Brukardt
@ 2005-07-27 17:36               ` Lucretia
  2005-07-27 21:28                 ` Randy Brukardt
  0 siblings, 1 reply; 20+ messages in thread
From: Lucretia @ 2005-07-27 17:36 UTC (permalink / raw)


Hmm, what I posted was a bit wrong. The event handler connect generics
actually take an Event_Handler_Class which all windows are rooted at.
Another example is when passing the items to sizers using "Add" after
the controlling parameter the next parameter is a Window_Class
(currently - it will be possible to add sizers as well in the future)
which is the item to add into the sizer, this is where I've needed to
use aliased.

In my minimal sample I derive a new Frame_Type and within that I have
declared a Button_Type instance, i.e.

type Minimal_Frame_Type is new Frame_Type with
  record
    ...
    Button : aliased Button_Type;
    ...
  end record;

Now, in the code I do this:

Add(Some_Sizer, Self.Button'Unchecked_Access...);

If I remove the aliased, it wont compile because Button is not aliased
(it is rooted at Object_Type like all other wxAda types).

If I keep aliased but use 'Access it doesn't compile because it is a
local object - I have also tried allocating the Minimal_Frame_Type
using new rather than having a "global" and it still requires the
aliased.

Because of all of this, I am seriously considering using pointers to
these instances rather than just instantiating them, i.e.:

type Minimal_Frame_Type is new Frame_Type with
  record
    ...
    Button : Button_Access;
    ...
  end record;

type Minimal_Frame_Access is access all Minimal_Frame_Type;

and having all primitives take an access parameter as the controlling
parameter.

Thanks,
Luke.




^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Private primitive operations available to entire package hierarchy. Can it be done?
  2005-07-27 17:36               ` Lucretia
@ 2005-07-27 21:28                 ` Randy Brukardt
  2005-07-28 10:09                   ` Lucretia
  0 siblings, 1 reply; 20+ messages in thread
From: Randy Brukardt @ 2005-07-27 21:28 UTC (permalink / raw)


"Lucretia" <lucretia9@lycos.co.uk> wrote in message
news:1122485760.918191.274380@f14g2000cwb.googlegroups.com...
...
> In my minimal sample I derive a new Frame_Type and within that I have
> declared a Button_Type instance, i.e.
>
> type Minimal_Frame_Type is new Frame_Type with
>   record
>     ...
>     Button : aliased Button_Type;
>     ...
>   end record;
>
> Now, in the code I do this:
>
> Add(Some_Sizer, Self.Button'Unchecked_Access...);

Is this in the user code, or in the implementation of the interface? If it's
in the implementation of the interface, do whatever you have to do. If it's
in the user code, though, I'd claim that the Add routine is incorrectly
specified -- it should simply pass the Button_Type object and the code
*internal* to the binding should be creating the access types.

> If I remove the aliased, it wont compile because Button is not aliased
> (it is rooted at Object_Type like all other wxAda types).

It will if Button is a parameter, rather than a component.

> If I keep aliased but use 'Access it doesn't compile because it is a
> local object - I have also tried allocating the Minimal_Frame_Type
> using new rather than having a "global" and it still requires the
> aliased.

Right. I've never found a case where I could actually use 'Access on an
object.

> Because of all of this, I am seriously considering using pointers to
> these instances rather than just instantiating them, i.e.:
>
> type Minimal_Frame_Type is new Frame_Type with
>   record
>     ...
>     Button : Button_Access;
>     ...
>   end record;
>
> type Minimal_Frame_Access is access all Minimal_Frame_Type;
>
> and having all primitives take an access parameter as the controlling
> parameter.

That's awful. If you do that, you're requiring your user to do memory
management for you, rather than the other way around. They'll be forced into
subpar syntax (explicit uses of aliased and 'Access), have runtime
accessibility errors, and other nastyness. And they would have no way to use
the containers library do the storage management for them.

My rule of thumb (not shared by all, mind you) is that explicit access types
in the user accessible specifications should be kept to an absolute minimum.
In Claw, we use them only to avoid copying of objects for query functions.
Everything else is passed as an object.

Internal to the library, of course, virtually everything is an access type.
But that sort of grunge is completely hidden from the user. We use the
predefined Finalize routine to insure that dangling pointers don't get left
around - when an object is finalized, it is removed from all internal
objects to which it is linked.

So, at the user level, I'd suggest something like:

    procedure Add (Sizer : Sizer_Type; Button : Button_Type'Class);

And the implementation of Add:

    procedure Add (Sizer : Sizer_Type; Button : Button_Type'Class) is
         My_Button : Any_Button_Access_Type := Button'Unchecked_Access;
         My_Sizer : Any_Sizer_Access_Type := Sizer'Unchecked_Access;
    begin
         -- Call the low level (C) routines:
         wx_Add (My_Sizer, My_Button);
         -- etc.
    end Add;

You might need to do some type conversions on the access types, but that's
OK as it doesn't usually generate any code.

                                Randy.






^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Private primitive operations available to entire package hierarchy. Can it be done?
  2005-07-27 21:28                 ` Randy Brukardt
@ 2005-07-28 10:09                   ` Lucretia
  2005-07-29  0:40                     ` Randy Brukardt
  0 siblings, 1 reply; 20+ messages in thread
From: Lucretia @ 2005-07-28 10:09 UTC (permalink / raw)


<quote>
> Add(Some_Sizer, Self.Button'Unchecked_Access..­.);

Is this in the user code, or in the implementation of the interface? If
it's
in the implementation of the interface, do whatever you have to do. If
it's
in the user code, though, I'd claim that the Add routine is incorrectly

specified -- it should simply pass the Button_Type object and the code
*internal* to the binding should be creating the access types.
</quote>

Yes, that line would be in the user code as Add is a primitive to
wx.Core.Sizer.Sizer_Type.

<quote>
> and having all primitives take an access parameter as the controlling
> parameter.

That's awful. If you do that, you're requiring your user to do memory
management for you, rather than the other way around. They'll be forced
into
subpar syntax (explicit uses of aliased and 'Access), have runtime
accessibility errors, and other nastyness. And they would have no way
to use
the containers library do the storage management for them.
</quote>

What's awful? Using access parameters as the controlling type or just
using instances the way I have been doing?

I don't really see what you mean about forcing the user into handling
the memory management. subpar syntax? Dunno what that means :-/

<quote>
And the implementation of Add:


    procedure Add (Sizer : Sizer_Type; Button : Button_Type'Class) is
         My_Button : Any_Button_Access_Type := Button'Unchecked_Access;

         My_Sizer : Any_Sizer_Access_Type := Sizer'Unchecked_Access;
    begin
         -- Call the low level (C) routines:
         wx_Add (My_Sizer, My_Button);
         -- etc.
    end Add;

You might need to do some type conversions on the access types, but
that's
</quote>

I thought that it was considered bad to get the access of a parameter
in this way?




^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Private primitive operations available to entire package hierarchy. Can it be done?
  2005-07-28 10:09                   ` Lucretia
@ 2005-07-29  0:40                     ` Randy Brukardt
  2005-08-02 15:55                       ` Lucretia
  0 siblings, 1 reply; 20+ messages in thread
From: Randy Brukardt @ 2005-07-29  0:40 UTC (permalink / raw)


"Lucretia" <lucretia9@lycos.co.uk> wrote in message
news:1122545378.984920.272260@g47g2000cwa.googlegroups.com...
...
>>> and having all primitives take an access parameter as the controlling
>>> parameter.

>>That's awful. If you do that, you're requiring your user to do memory
management
>>for you, rather than the other way around. They'll be forced into subpar
syntax
>>(explicit uses of aliased and 'Access), have runtime accessibility errors,
and
>>other nastyness. And they would have no way to use the containers library
>>do the storage management for them.

>What's awful? Using access parameters as the controlling type or just
>using instances the way I have been doing?

Using access types in the user interface. I believe that they should be
limited to cases where there is no other choice (generally because of
copying issues).

> I don't really see what you mean about forcing the user into handling
> the memory management. subpar syntax? Dunno what that means :-/

If you use access types in the parameters, then the users of your interface
will have to either:

* use an allocator (new) to create objects. In that case, they'll have to
use Unchecked_Deallocation to get rid of them. That puts a lot of effort on
the user that they may not need the power of (often stack allocation is just
fine for objects); or
* declare objects with the ugly "aliased" syntax, and worse, have to use the
'Unchecked_Access attribute in most calls. Which means a lot of extra typing
(and more importantly, reading) that has nothing to do with their program.

Moreover, if you use access types in this way, you're preventing the users
from using an Ada.Containers container to do their memory management. They'd
have to put access values into the container, and do their own memory
management on those values -- pretty much defeating the purpose of a
container.

There is also the issue of accessibility; you can get runtime failures if
user pass 'Access of a local object and you want to store that into some
library-level type (even for immediate, short-term use).

In Ada 95, you can't pass null, either, so even that tiny utility is not
available.

My motto is to let the user of my libraries to determine the memory
management most appropriate for their uses, and that means passing objects,
not access values. Given Ada's rules, the generated code is the same either
way anyway - indeed, object passing is likely to be cheaper (no
accessibility level to pass). Just say no to anonymous access parameters.
:-) [Personally, I believe that anonymous access types were a complete
mistake; the only issue was missing "in out" parameters for functions. There
is no technical advantage to using anonymous access types in any situation,
and many pitfalls.]

<quote>
And the implementation of Add:


    procedure Add (Sizer : Sizer_Type; Button : Button_Type'Class) is
         My_Button : Any_Button_Access_Type := Button'Unchecked_Access;

         My_Sizer : Any_Sizer_Access_Type := Sizer'Unchecked_Access;
    begin
         -- Call the low level (C) routines:
         wx_Add (My_Sizer, My_Button);
         -- etc.
    end Add;

You might need to do some type conversions on the access types, but
that's
</quote>

> I thought that it was considered bad to get the access of a parameter
> in this way?

I sure hope not, its the central tenet of the Claw design. It *is* necessary
to be careful about lifetime issues. There is nothing to worry about if the
access value will not be used any longer than the duration of the call - the
parameter cannot be finalized while the call is active (unless the program
is erroneous anyway - it would probably crash for reasons having nothing to
do with your library if that happened). If you need to use it longer, then
you have to make sure that you have a way to destroy the access value if the
object gets finalized while you are still holding onto the access value.
Claw uses controlled types for this; when an object is finalized, the object
is removed from all lists and other objects that it is in (obviously, that
means making sure that the object keeps track of every place that it is
linked).

Note that these issues are exactly the same if you use access types. The
only difference is that you might get a runtime failure if the user used
'Access instead of 'Unchecked_Access. (By doing this in your own code, you
can avoid having to require your users to use 'Unchecked_Access for their
calls to work reliably.)

                                       Randy.






^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Private primitive operations available to entire package hierarchy. Can it be done?
  2005-07-29  0:40                     ` Randy Brukardt
@ 2005-08-02 15:55                       ` Lucretia
  2005-08-03 18:26                         ` Lucretia
  2005-08-03 20:03                         ` Randy Brukardt
  0 siblings, 2 replies; 20+ messages in thread
From: Lucretia @ 2005-08-02 15:55 UTC (permalink / raw)


<quote>
If you use access types in the parameters, then the users of your
interface
will have to either:

* use an allocator (new) to create objects. In that case, they'll have
to
use Unchecked_Deallocation to get rid of them. That puts a lot of
effort on
the user that they may not need the power of (often stack allocation is
just
fine for objects); or
</quote>

Well this can be hidden away inside a "Create" subprogram as per
GtkAda, and as you have to create this kind of "constructor" for Ada
types anyway, I don't see the problem?

e.g. I currently have a New_Frame which will do any construction
necessary for this type, basically it'll call the C constructor
function which calls "new wxFrame(...)" and returns the pointer back to
Ada which stores it inside wxObject in the wx.Base.Object.Object_Type
as a System.Address.

If I then derive a new frame type (My_Frame), I should also create a
New_My_Frame primitive which calls New_Frame first on the object, then
do any other construction necessary for My_Frame.

<quote>
* declare objects with the ugly "aliased" syntax, and worse, have to
use the
'Unchecked_Access attribute in most calls. Which means a lot of extra
typing
(and more importantly, reading) that has nothing to do with their
program.
</quote>

Well, I have Limited_Controlled as my root tagged type and I still have
to use aliased, so that blatantly doesn't work, unless I'm missing
something.

<quote>
Moreover, if you use access types in this way, you're preventing the
users
from using an Ada.Containers container to do their memory management.
They'd
have to put access values into the container, and do their own memory
management on those values -- pretty much defeating the purpose of a
container.
</quote>

Because the containers have their own access types inside the packages,
right? So, you're saying I should do the following in each of my
packages:

type Some_Type is new Some_Base_Type with private;
type Some_Access is access all Some_Type;
type Some_View is access constant Some_Type;

<quote>
If you need to use it longer, then you have to make sure that you have
a way to destroy the access value if the object gets finalized while
you are still holding onto the access value. Claw uses controlled types
for this; when an object is finalized, the object
is removed from all lists and other objects that it is in (obviously,
that means making sure that the object keeps track of every place that
it is linked).
</quote>

So, you get hold of the access of every type constructed and keep a
reference counted list of them?

With the way you have to start the wxWidgets library up, it's more than
fiddly. I've not been able to get reference counting working reliably.
Also getting the app to finalize last is particularly difficult but I
haven't played with it for a while.

Thanks,
Luke.




^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Private primitive operations available to entire package hierarchy. Can it be done?
  2005-08-02 15:55                       ` Lucretia
@ 2005-08-03 18:26                         ` Lucretia
  2005-08-03 20:04                           ` Randy Brukardt
  2005-08-03 20:03                         ` Randy Brukardt
  1 sibling, 1 reply; 20+ messages in thread
From: Lucretia @ 2005-08-03 18:26 UTC (permalink / raw)


As for the aliased problem I was having, I sorted that out as I was
creating access types inside my packages and using the *_Class type
which was "access all *_Type'Class" in the parameters instead of just
using ": in Some_Type'Class" DOH!




^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Private primitive operations available to entire package hierarchy. Can it be done?
  2005-08-02 15:55                       ` Lucretia
  2005-08-03 18:26                         ` Lucretia
@ 2005-08-03 20:03                         ` Randy Brukardt
  2005-08-08 18:04                           ` Lucretia
  1 sibling, 1 reply; 20+ messages in thread
From: Randy Brukardt @ 2005-08-03 20:03 UTC (permalink / raw)


"Lucretia" <lucretia9@lycos.co.uk> wrote in message
news:1122998146.914353.174110@g44g2000cwa.googlegroups.com...
> <quote>
> If you use access types in the parameters, then the users of your
interface
> will have to either:
>
> * use an allocator (new) to create objects. In that case, they'll have to
> use Unchecked_Deallocation to get rid of them. That puts a lot of effort
on
> the user that they may not need the power of (often stack allocation is
just
> fine for objects); or
> </quote>
>
> Well this can be hidden away inside a "Create" subprogram as per
> GtkAda, and as you have to create this kind of "constructor" for Ada
> types anyway, I don't see the problem?

The problem is storage leakage. You can't (in Ada) put a finalize routine on
an access type, so there is no way to reclaim the memory when the object
disappears. You'd have to use an explicit Destroy routine, and that puts the
burden on the users, and it doesn't work very well, either, because it isn't
safe against exceptions propagating, aborts, and the like. Our earliest
versions of Claw required such routines, and we found that they were very
difficult to use and debug, because any mistake tended to leave dead objects
around -- which then raised more exceptions and eventually caused the system
to deadlock.

> e.g. I currently have a New_Frame which will do any construction
> necessary for this type, basically it'll call the C constructor
> function which calls "new wxFrame(...)" and returns the pointer back to
> Ada which stores it inside wxObject in the wx.Base.Object.Object_Type
> as a System.Address.
>
> If I then derive a new frame type (My_Frame), I should also create a
> New_My_Frame primitive which calls New_Frame first on the object, then
> do any other construction necessary for My_Frame.

Right. I believe that is best done on objects, not on accesses. (Claw uses
procedure constructors because copying of objects inherent in Ada 95
functions is problematical.)

> <quote>
> * declare objects with the ugly "aliased" syntax, and worse, have to use
the
> 'Unchecked_Access attribute in most calls. Which means a lot of extra
typing
> (and more importantly, reading) that has nothing to do with their program.
> </quote>
>
> Well, I have Limited_Controlled as my root tagged type and I still have
> to use aliased, so that blatantly doesn't work, unless I'm missing
> something.

You must be missing something, because its not necessary *in the user code*.
I've tried to explain that several times already, and I don't think I can
explain it any better than I already have. And I don't want to try to design
your interface for you...

> <quote>
> Moreover, if you use access types in this way, you're preventing the users
> from using an Ada.Containers container to do their memory management.
They'd
> have to put access values into the container, and do their own memory
> management on those values -- pretty much defeating the purpose of a
container.
> </quote>
>
> Because the containers have their own access types inside the packages,
> right?

No, because you can't get an access to the element stored in a container.
(Well, that's not *quite* true, you could use 'Address and
Address_to_Access_Conversions, but that's certainly not guaranteed to work.)

> So, you're saying I should do the following in each of my packages:
>
> type Some_Type is new Some_Base_Type with private;
> type Some_Access is access all Some_Type;
> type Some_View is access constant Some_Type;

I would not declare access types in the user part of the specification. If
the user needs them, they can declare them easily enough, and if you declare
them, they can't use a custom storage pool.

If *you* need them for the implementation, declare them in the private part.

My rule is to never force the user to use access types - give them the
maximum flexibility by allowing them to chose the appropriate way to declare
the objects of your binding.

But if you really need them, they ought to be classwide (I usually use "any"
in the name to reflect this):

type Any_Some_Access is access all Some_Type'Class;
type Any_Some_View is access constant Some_Type'Class;

For Ada O-O programming, anything that is not primitive or an object
declaration that is specific is suspect. (Sometimes you have to make
exceptions for constructors.)

> <quote>
> If you need to use it longer, then you have to make sure that you have
> a way to destroy the access value if the object gets finalized while
> you are still holding onto the access value. Claw uses controlled types
> for this; when an object is finalized, the object
> is removed from all lists and other objects that it is in (obviously,
> that means making sure that the object keeps track of every place that
> it is linked).
> </quote>
>
> So, you get hold of the access of every type constructed and keep a
> reference counted list of them?

Not exactly. In Claw, we have a list of all top-level windows of the
application anyway. Child windows are linked to their parents, and
vice-versa. So we can traverse all the windows by following that top-level
list. When a window *object* is being destroyed, we traverse all of the
windows and remove any accesses to the object, whereever they are. We don't
reference count, because we're not tracking the accesses, we're tracking the
objects. (Remember, you can only manage a collection of objects in Ada, not
access values, as you can't have Adjust/Finalize on an access value.)

Other types of objects work similarly; typically, they contain a list of all
windows that they've been attached to. When one is finalized, it is removed
from any windows that it is attached to (which involves not only removing
the links, but also issuing any Windows operations needed to remove the
objects).

We do use something like reference counting to allow Window objects to be
assigned. But that capability was a mistake - we wouldn't do it if starting
over - so I won't try to describe it.

So the main capability (and cost) is that each object has to contain a list
of everywhere inside of the binding where it is linked, so it can be removed
if the object is finalized (or explicitly destroyed, for that matter).

> With the way you have to start the wxWidgets library up, it's more than
> fiddly. I've not been able to get reference counting working reliably.
> Also getting the app to finalize last is particularly difficult but I
> haven't played with it for a while.

Termination was a real pain in Claw; for the longest time we used a
subprogram that you had to call before exiting. Otherwise the program would
deadlock -- and it usually did in practice, because an exception got raised
while finalizing something else, or someone aborted a task, or other things.
We eventually got it worked out.

                             Randy.






^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Private primitive operations available to entire package hierarchy. Can it be done?
  2005-08-03 18:26                         ` Lucretia
@ 2005-08-03 20:04                           ` Randy Brukardt
  0 siblings, 0 replies; 20+ messages in thread
From: Randy Brukardt @ 2005-08-03 20:04 UTC (permalink / raw)


"Lucretia" <lucretia9@lycos.co.uk> wrote in message
news:1123093593.264508.256310@f14g2000cwb.googlegroups.com...
> As for the aliased problem I was having, I sorted that out as I was
> creating access types inside my packages and using the *_Class type
> which was "access all *_Type'Class" in the parameters instead of just
> using ": in Some_Type'Class" DOH!

Great. You usually can use type conversions to work around such mismatches
(conversions on access types are usually allowed).

                         Randy.






^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Private primitive operations available to entire package hierarchy. Can it be done?
  2005-08-03 20:03                         ` Randy Brukardt
@ 2005-08-08 18:04                           ` Lucretia
  2005-08-08 20:47                             ` Randy Brukardt
  0 siblings, 1 reply; 20+ messages in thread
From: Lucretia @ 2005-08-08 18:04 UTC (permalink / raw)


<quote>
We do use something like reference counting to allow Window objects to
be
assigned. But that capability was a mistake - we wouldn't do it if
starting
over - so I won't try to describe it.
</quote>

I started with a non-limited hierarchy that could be copied but found
that not all wxWidgets classes can be copied as the copy constructor is
private in certain objects, e.g. all wxWindow derived types. So, I now
have a limited hierarchy, even though certain objects need to be
copiable, e.g. wxEvent derived types.

Thanks,
Luke.




^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: Private primitive operations available to entire package hierarchy. Can it be done?
  2005-08-08 18:04                           ` Lucretia
@ 2005-08-08 20:47                             ` Randy Brukardt
  0 siblings, 0 replies; 20+ messages in thread
From: Randy Brukardt @ 2005-08-08 20:47 UTC (permalink / raw)


"Lucretia" <lucretia9@lycos.co.uk> wrote in message
news:1123524248.690333.24270@g14g2000cwa.googlegroups.com...
> <quote>
> We do use something like reference counting to allow Window objects to
> be
> assigned. But that capability was a mistake - we wouldn't do it if
> starting
> over - so I won't try to describe it.
> </quote>
>
> I started with a non-limited hierarchy that could be copied but found
> that not all wxWidgets classes can be copied as the copy constructor is
> private in certain objects, e.g. all wxWindow derived types. So, I now
> have a limited hierarchy, even though certain objects need to be
> copiable, e.g. wxEvent derived types.

There are ways around that. But we ultimately found that they made it very
hard to cleanly add extension components to derived window classes. So many
of our programs include
    procedure Adjust (Object : in out Whatever_Window) is
    begin
          raise Program_Error;
    end Adjust;

Effectively making that type limited (without the compile-time checking).
But of course, if we were going to do that, we might as well have made the
types limited in the first place and avoided the complications. So I agree
with your intent to make them limited.

                        Randy.






^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2005-08-08 20:47 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-07-07 16:06 Private primitive operations available to entire package hierarchy. Can it be done? Lucretia
2005-07-07 16:17 ` OT: Joke Adrien Plisson
2005-07-07 16:24   ` Matthew Heaney
2005-07-07 19:10 ` Private primitive operations available to entire package hierarchy. Can it be done? Randy Brukardt
2005-07-13 15:40   ` Lucretia
2005-07-19 23:19     ` Randy Brukardt
2005-07-20 18:14       ` Lucretia
2005-07-21  3:10         ` Randy Brukardt
2005-07-25 18:14           ` Lucretia
2005-07-25 23:58             ` Randy Brukardt
2005-07-27 17:36               ` Lucretia
2005-07-27 21:28                 ` Randy Brukardt
2005-07-28 10:09                   ` Lucretia
2005-07-29  0:40                     ` Randy Brukardt
2005-08-02 15:55                       ` Lucretia
2005-08-03 18:26                         ` Lucretia
2005-08-03 20:04                           ` Randy Brukardt
2005-08-03 20:03                         ` Randy Brukardt
2005-08-08 18:04                           ` Lucretia
2005-08-08 20:47                             ` Randy Brukardt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox