From: xorque on 13 Nov 2009 15:12 Hello. I'm trying to write an archive/directory abstraction in a similar vein to PhysicsFS but am at a bit of a loss as to how to design the archiver interface: with Path; package Archiver is type Archiver_t is abstract tagged limited private; type Archiver_Class_Access_t is access Archiver_t'Class; procedure Init (Archiver : out Archiver_t) is abstract; function Can_Mount (Archiver : in Archiver_t; Path : in Path.Real_t) return Boolean is abstract; type File_t is abstract tagged limited private; type File_Class_Access_t is access File_t'Class; procedure Open (Archiver : in Archiver_t; Path : in Path.Virtual_t; File : out File_t) is abstract; procedure Close (File : in out File_t) is abstract; private type Archiver_t is abstract tagged limited null record; type File_t is abstract tagged limited null record; end Archiver; The idea of the above is that the main part of the library only deals with archivers and "files" (which might only really be pointers to entries in Zip files, for example) by 'Class. The problem with the above is that: archiver.ads:18:13: operation can be dispatching in only one type Hopefully someone here knows a better way to handle this.
From: Dmitry A. Kazakov on 13 Nov 2009 15:34 On Fri, 13 Nov 2009 12:12:18 -0800 (PST), xorque wrote: > I'm trying to write an archive/directory abstraction in a similar vein > to PhysicsFS > but am at a bit of a loss as to how to design the archiver interface: > > with Path; > > package Archiver is > > type Archiver_t is abstract tagged limited private; > type Archiver_Class_Access_t is access Archiver_t'Class; > > procedure Init > (Archiver : out Archiver_t) is abstract; > > function Can_Mount > (Archiver : in Archiver_t; > Path : in Path.Real_t) return Boolean is abstract; > > type File_t is abstract tagged limited private; > type File_Class_Access_t is access File_t'Class; > > procedure Open > (Archiver : in Archiver_t; > Path : in Path.Virtual_t; > File : out File_t) is abstract; > > procedure Close > (File : in out File_t) is abstract; > > private > > type Archiver_t is abstract tagged limited null record; > > type File_t is abstract tagged limited null record; > > end Archiver; > > The idea of the above is that the main part of the library only deals with > archivers and "files" (which might only really be pointers to entries in Zip > files, for example) by 'Class. > > The problem with the above is that: > > archiver.ads:18:13: operation can be dispatching in only one type > > Hopefully someone here knows a better way to handle this. Ada does not support multiple dispatch of this form. For simplicity consider it does not support MD at all. According to your code Open is doubly dispatching in Archiver_t and File_t arguments. That does not work (unfortunately). You have to choose one and make another class-wide. E.g. procedure Open (Archiver : Archiver_t'Class; -- Class-wide Path : Virtual_t; File : in out File_t) is abstract; This would be a primitive operation of File_t only. P.S. If you indeed have to do MD, you should emulate it manually, by dispatching within Open to some primitive operation of Archiver_t. P.P.S. Do not use access types unless you need them. P.P.P.S. Replace tagged limited with Ada.Finalization.Limited_Controlled, sooner or later you almost certainly will need finalization and initialization. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de
From: xorque on 13 Nov 2009 15:43 Thanks for the response. It may be that I don't want to design the interface like the above at all. The only real requirement is that: Archivers use a common protocol: Code just sees operations on Archiver_t'Class and doesn't know if it's reading from a Zip, RAR, directory, etc. Presumably, then, when I open a file using an operation from an archiver, I can't know about the implementation of the actual file as it's private to the archiver. Hence, I've ended up with two private tagged types. Is there a better way (I've not ignored your other suggestions, I'm just exploring other possibilities first)?
From: xorque on 13 Nov 2009 15:44 On Nov 13, 8:34 pm, "Dmitry A. Kazakov" <mail...(a)dmitry-kazakov.de> wrote: ..> > P.P.P.S. Replace tagged limited with Ada.Finalization.Limited_Controlled, > sooner or later you almost certainly will need finalization and > initialization. Agreed. It was always intended, just not implemented there for simplicity's sake.
From: Dmitry A. Kazakov on 13 Nov 2009 16:14
On Fri, 13 Nov 2009 12:43:42 -0800 (PST), xorque wrote: > The only real requirement is that: > > Archivers use a common protocol: Code just sees operations > on Archiver_t'Class and doesn't know if it's reading from a Zip, RAR, > directory, etc. > > Presumably, then, when I open a file using an operation from an > archiver, I can't know about the implementation of the actual file > as it's private to the archiver. > > Hence, I've ended up with two private tagged types. Is there a better > way (I've not ignored your other suggestions, I'm just exploring other > possibilities first)? MD is customary replaced my mix-in: 1. Standard mix-in: type File_Type is abstract new Ada.Finalization.Limited_Controlled with null record; procedure Open ( File : in out File_Type; Path : String ) is abstract; procedure Close (File : in out File_Type) is abstract; procedure Read ...; procedure Write ...; Files know nothing about archives. Archive has a file as a mixin: type Archiver_Type (Transport : not null access File_Type'Class) is new Ada.Finalization.Limited_Controlled with null record; procedure Open (Archiver : in out Archiver_Type; Path : String); Open of Archive_Type calls to Open of Archive.Transport. Same with other operations. They all are defined in terms of the operations of File_Type. Class through Archive.Transport are dispatching, because it is class-wide. 2. Generic mix-in. You can put Archive in the hierarchy of File_Type. The implementation of Archive_Type can be generic taking a descendant of File_Type and then extending it in the generic body. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de |