From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.3 required=5.0 tests=BAYES_00,INVALID_MSGID autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,9a7e0c43216f4def X-Google-Attributes: gid103376,public From: Matthew Heaney Subject: Re: "out" or "access" Date: 1998/10/29 Message-ID: #1/1 X-Deja-AN: 406199848 Sender: matt@mheaney.ni.net References: <908956499.754394@dedale.pandemonium.fr> <70mo3h$gll$1@cf01.edf.fr> NNTP-Posting-Date: Wed, 28 Oct 1998 21:30:57 PDT Newsgroups: comp.lang.ada Date: 1998-10-29T00:00:00+00:00 List-Id: Robert A Duff writes: > Another eg, if "type T2 is new T1...", then T2 implicitly converts to > T1'Class, but access-to-T2 does not implicitly convert to > access-to-T1'Class, except in the case of access parameters -- I would > like a more general feature, to avoid making "safe" conversions > explicit. Agreed. It only adds syntactic overhead, with no added value. Worse, it makes you not pay attention to those type casts that really do matter. > Given the specific problem access params were intended to solve, > "access constant" made little sense. But in restrospect, I think we > should have allowed it. We absolutely need access constant params. It's the only (safe) way to implement a factory method that returns an iterator, so that you can traverse a read-only data structure. For example: generic type Item_Type is private; ... package Queues is type Root_Queue is abstract tagged limited private; ... type Root_Iterator is abstract tagged private; function New_Iterator (Queue : access constant Root_Queue) return Root_Iterator'Class is abstract; function Done (Iterator : Root_Iterator) return Boolean is abstract; procedure Get_Item (Iterator : Root_Iterator) return Item_Type is abstract; procedure Advance (Iterator : in out Root_Iterator); ... end; Every type that derives from Root_Queue is required to implement a factory method (New_Iterator), that allows you to iterate over that structure. This way, you can iterate over class-wide objects: generic with Image (Item : Item_Type) return String is <>; procedure Queues.Put (Queue : in Root_Queue'Class); procedure Queues.Put (Queue : in Root_Queue'Class) is Iter : Root_Iterator'Class := New_Iterator (Queue); begin while not Done (Iter) loop Ada.Text_IO.Put (Image (Get_Item (Iter))); Advance (Iter); end loop; end; Without access constant, you have to use access, which requires a read-write (and aliased) view of the object. It's not so bad in the example above, because we could always declare procedure Put to take the queue object as in out. But this will not work for functions, ie function "=" (L, R : Root_Queue'Class) return Boolean; because functions can't take in out params, and a comparison of class-wide objects should only be a read-only activity anyway. So you have to work around this by declaring functions to take access params: function "=" (L, R : access Root_Queue'Class) return Boolean; which is really ugly. Not having access constant parameters tends to cause a ripple effect, were you have to go back declare objects as aliased, or to change subprograms that have args of mode in to mode in out or access. In my work on the Ada Components Library, I've worked around this by resorting to ugly hacks like using System.Address_To_Access_Conversions and parameters of a named access-to-constant type. The latter approach means I lose the ability to dispatch, which is a REAL bummer. Please, let's fix this omission, sooner rather than later. We need access constant parameters.