From: Felix Krause <contact@flyx.org>
Subject: Re: Smart Pointers and Tagged Type Hierarchies
Date: Thu, 27 Jul 2017 21:30:59 +0200
Date: 2017-07-27T21:30:59+02:00 [thread overview]
Message-ID: <2017072721305951845-contact@flyx.org> (raw)
In-Reply-To: ol5j8i$10s8$1@gioia.aioe.org
On 2017-07-24 19:53:54 +0000, Dmitry A. Kazakov said:
> On 2017-07-24 17:41, Felix Krause wrote:
>
>> Now I am wondering what others think of these approaches. Are there
>> alternatives? Which one would be better from a user perspective?
>
> I am using generic pointer (Handle), which can be instantiated later
> with any derived type from the base reference counting type. See Simple
> Components:
>
> http://www.dmitry-kazakov.de/ada/components.htm#Objects_etc
>
> This is your second approach but with object pointer type passed as a
> second generic parameter.
>
> generic
> type Object_Type (<>) is abstract new Entity with private;
> type Object_Type_Ptr is access Object_Type'Class;
> package Object.Handle is
> type Handle is new Ada.Finalization.Controlled with private;
>
> Users of smart pointer need not to be generic. I don't know why you
> think it is necessary.
Using your types, let's say I have
type Entity_Access is access Entity'Class;
package Entity_Handle is new Object.Handle (Entity, Entity_Access);
type A_Type is new Entity with private;
type A_Access is access A_Type'Class;
package A_Handle is new Object.Handle (A_Type, A_Access);
Now some subroutine wants to take an Entitiy as parameter, or more precisely, a
Handle to an Entity. If I specify this:
procedure Do_Something (E : Entity_Handle.Handle);
I cannot call this procedure with an A_Handle.Handle. So I'd need to do:
generic
with package Actual_Handle is new Object.Handle (<>);
procedure Do_Something (E : Actual_Handle.Handle);
I don't see how I can prevent this using your approach.
> Regarding hierarchy of types and additional operations and the problem
> of exposing the implementation type. You can use delegation:
>
> E.g. if you have your File_Stream_Object and File_Stream_Reference, you
> define a File_Stream_Interface:
>
> type File_Stream_Interface is interface;
> procedure Foo (Stream : in out File_Stream_Interface) is abstract;
>
> Then both object and reference implement the interface:
>
> type File_Stream_Object is
> new Instance and File_Stream_Interface ...
> overriding procedure Foo (Stream : in out File_Stream_Reference);
>
> type File_Stream_Reference is
> new Reference and File_Stream_Interface ...
> overriding procedure Foo (Stream : in out File_Stream_Reference);
>
> From second Foo you call the first after dereferencing. Now you can
> hide File_Stream_Object and expose only File_Stream_Interface and
> File_Stream_Reference. You can also derive from File_Stream_Object and
> File_Stream_Reference adding new interfaces. The latter has a drawback
> that you will have to convert pointer to a more specific class.
>
> ------------------------------------
> It is quite tedious because:
>
> 1. Delegation cannot be automated in Ada;
> 2. Pointer are not promoted upon inheritance.
>
> Otherwise this schema works well.
Thanks for this. It is probably not the approach I will use, but not a
bad idea.
Another question using generics: If I do use a generic package for the
smart pointers, is there a good way to put the instance of that package
inside the package that defines the derived type?
Example (starts with the generic code in my original post):
package Stream is
type Instance is abstract limited tagged private;
-- fetches an event from the stream
procedure Fetch (Object : in out Instance; Ret : out Event) is abstract;
private
type Instance is abstract tagged limited record
Refcount : Natural := 1;
end record;
end Stream;
generic
type Implementation is new Stream.Instance with private;
package Stream.Smart is
type Reference is new Ada.Finalization.Controlled with private;
-- reference-counting implementation
overriding procedure Adjust (Object : in out Reference);
overriding procedure Finalize (Object : in out Reference);
private
type Implementation_Access is access all Implementation'Class;
type Reference is new Ada.Finalization.Controlled with record
Data : access Implementation_Access;
end record;
end Stream.Smart;
package File_Stream is
type Instance is new Stream.Instance with private;
package Smart is new Stream.Smart (Instance);
private
type Instance is new Stream.Instance with record
File : Ada.Text_IO.File_Access;
end record;
end File_Stream;
This does not compile because I cannot instantiate Stream.Smart with
the incomplete File_Stream.Instance type. What would work is to have
instead a child package:
package File_Stream.Smart is new Stream.Smart (File_Stream.Instance);
But with this, I am not able to define any subroutines in the
File_Stream package that take a smart pointer.
--
Regards,
Felix Krause
next prev parent reply other threads:[~2017-07-27 19:30 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-07-24 15:41 Smart Pointers and Tagged Type Hierarchies Felix Krause
2017-07-24 19:53 ` Dmitry A. Kazakov
2017-07-27 19:30 ` Felix Krause [this message]
2017-07-27 20:42 ` Dmitry A. Kazakov
2017-07-24 21:24 ` Chris Moore
2017-07-27 19:38 ` Felix Krause
2017-08-01 4:07 ` Randy Brukardt
2017-07-26 17:53 ` Ivan Levashev
2017-07-28 9:21 ` AdaMagica
2017-07-30 19:45 ` briot.emmanuel
2017-08-01 3:43 ` Randy Brukardt
2017-08-01 7:36 ` Dmitry A. Kazakov
2017-08-01 22:41 ` Randy Brukardt
2017-08-02 6:28 ` Dmitry A. Kazakov
2017-08-02 19:26 ` Randy Brukardt
replies disabled
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox