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=0.1 required=5.0 tests=BAYES_00,PDS_OTHER_BAD_TLD autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,bd40601768eaf8fd X-Google-Attributes: gid103376,public From: "Matthew Heaney" Subject: Re: Proposed Ada features (was Re: Array of Variant Records Question...) Date: 1999/09/10 Message-ID: <37d9658c@news1.prserv.net> X-Deja-AN: 523515555 Content-transfer-encoding: 7bit References: <7r5vh3$imu1@svlss.lmms.lmco.com> <37d6a45c@news1.prserv.net> <37d6ccb6@news1.prserv.net> <7r77i8$i08$1@nnrp1.deja.com> <37d7c116@news1.prserv.net> <7r8t21$ov5$1@nnrp1.deja.com> <37D955B5.A018835D@rational.com> Content-Type: text/plain; charset="US-ASCII" X-Complaints-To: abuse@prserv.net X-Trace: 10 Sep 1999 20:09:48 GMT, 32.101.8.43 Organization: Global Network Services - Remote Access Mail & News Services Mime-version: 1.0 Newsgroups: comp.lang.ada Date: 1999-09-10T00:00:00+00:00 List-Id: In article <37D955B5.A018835D@rational.com> , Mark Lundquist wrote: > And Matt, don't forget "is limited access"... As I recall you were the > one who mentioned this a while back, but for some reason it didn't make > your wish list. It's implied by the downward funarg request. Limited access types have been proposed as a (partial?) solution to that problem. The reason I want "access constant" params is to be able to use the automatic resource locking idiom, without having to use Chap 13 tricks. I'll use my fav example. Suppose we have a concurrent stack. A semaphore is part of the representation of the stack, and it's used to Seize and Release the stack at the beginning and end of every stack operation. For example, the Semaphore_Control type looks like this: type Semaphore_Control (Semaphore : access Semaphore_Type) is limited private; Semaphore_Control type privately derives from Limited_Controlled, and calls Semaphore.Seize during Initialize, and Semaphore.Release during Finalize. To implement Push, you'd do this: procedure Push (Item : in Item_Type; Stack : in out Stack_Type) is Control : Semaphore_Control (Stack.Semaphore'Access); begin Stack.Top := Stack.Top + 1; Stack.Items (Stack.Top) := Item; end; Everything's hunky-dory here, because the Stack is a variable view. (Let's assume it's also an aliased view, because the stack is either publicly or privately tagged.) But now let's try to implement Get_Top: function Get_Top (Stack : Stack_Type) return Item_Type is Control : Semaphore_Control (Stack.Semaphore'Access); begin return Stack.Items (Stack.Top); end; This code is illegal, because this is a constant view of the Stack, not a variable view. The access discriminant of the Control object requires a variable view. However, if we were able to declare the Control object this way: type Semaphore_Control (Semaphore : access constant Semaphore_Type) is limited private; then only a constant view of the Stack is necessary, and Get_Top can be implemented as I've shown above. Now, there are two ways to solve the problem: 1) Pass the stack as an access parameter to Get_Top. This works, but it makes it seem as if the Stack is being modified during Get_Top. Worse, it makes it impossible to invoke Get_Top in a context where we have a read-only view of the stack. So we prefer to implement Get_Top using an in-mode param. 2) Use System.Address_To_Access_Conversions. The stack is a by-reference type, so Stack'Address is legal(?) per RM95 13.3 (16). We feed the Stack's address to To_Pointer, which gives us an access object designating a variable view of the Stack. We then refer to the Stack via the access object, instead of via the in-mode parameter. I would prefer to not ever have to invoke RM95 13.3 (16), but now I often have to, being careful to always implement the type in such a way as to guarantee that it's passed by-reference. Another time this would be handy is to implement a factory method constructor for iterators. For example, suppose I want to do implement a class-wide operation to print a stack (useful for debugging): procedure Print (Stack : in Root_Stack_Type'Class) is Iterator : Root_Iterator_Type'Class := Start_At_Top (Stack'Access); begin The factory method looks like this: function Start_At_Top (Stack : access Root_Stack_Type) return Root_Iterator_Type'Class; The iterator needs a pointer to the stack, AND Start_At_Top needs to be primitive, so it will dispatch. That means an access parameter. But, the invokation above is illegal, because I can't take the 'Access of a constant view of the stack. However, if I were able to declare the factory method this way: function Start_At_Top (Stack : access constant Root_Stack_Type) return Root_Iterator_Type'Class; then everything would be hunky-dory. I solve the problem now by passing the stack as an in-mode parameter, and internally turn that into an access object. However, I lose all the accessibility checks, so I'm depending on users to Do The Right Thing. I discuss these techniques in several posts I've submitted to the ACM Ada95 Design Patterns list, and will be discussing them again in my Design Patterns tutorial at this year's SIGAda conference. (Search for "13.3", and see what drops out.) >> > 2) the ability to cast away const w/o using >> Sys.Addr_To_Acc_Convs > What I haven't figured out is why you would want to do this. Same with > "mutable". This is closely related to the problem above. Basically, what I really want is functions with in-out parameters, but this will never happen. However, you do get most of what you need already, by passing the object as an access parameter. You could argue for its inclusion for the same reasons it's in C++. Sometimes, you have an operation that, publicly, doesn't change the state of the object. But privately, it may make sense to make a state change, say, to record some information about the call. The canonical example of this is the function Random. It changes the state of the Generator, which is an in-mode parameter.