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