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.9 required=5.0 tests=BAYES_00,FREEMAIL_FROM autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,9d303864ae4c70ad X-Google-Attributes: gid103376,public X-Google-ArrivalTime: 2004-04-15 22:40:02 PST Path: archiver1.google.com!news1.google.com!news.glorb.com!news-feed01.roc.ny.frontiernet.net!nntp.frontiernet.net!nntp.giganews.com.MISMATCH!border1.nntp.ash.giganews.com!border2.nntp.sjc.giganews.com!border1.nntp.sjc.giganews.com!nntp.giganews.com!local1.nntp.sjc.giganews.com!nntp.comcast.com!news.comcast.com.POSTED!not-for-mail NNTP-Posting-Date: Fri, 16 Apr 2004 00:40:01 -0500 Date: Fri, 16 Apr 2004 01:40:01 -0400 From: "Robert I. Eachus" User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:1.4) Gecko/20030624 Netscape/7.1 (ax) X-Accept-Language: en-us, en MIME-Version: 1.0 Newsgroups: comp.lang.ada Subject: Re: Reprise: 'in out' parameters for functions References: <5ad0dd8a.0404090512.15af2908@posting.google.com> <5ad0dd8a.0404091828.6e79bb4e@posting.google.com> <8Oadneu6eY9pweDdRVn-hA@comcast.com> <5ad0dd8a.0404151752.4f598e1a@posting.google.com> In-Reply-To: <5ad0dd8a.0404151752.4f598e1a@posting.google.com> Content-Type: text/plain; charset=us-ascii; format=flowed Content-Transfer-Encoding: 7bit Message-ID: NNTP-Posting-Host: 24.147.90.114 X-Trace: sv3-Q9vu6Hc4Uq9FjQdv9wa5q3uzlP8Q4SzDJUst1CvovzvJe7Ju+hyEmrPDUwx2TRexRvt5y4eUAeDu4y5!i1BrRVJcMnxQwkHdamyNnjiRHCwl/ghnqt0Gelsjr7cn3dq+sNSYZ+ylc5hX1Q== X-Complaints-To: abuse@comcast.net X-DMCA-Complaints-To: dmca@comcast.net X-Abuse-and-DMCA-Info: Please be sure to forward a copy of ALL headers X-Abuse-and-DMCA-Info: Otherwise we will be unable to process your complaint properly X-Postfilter: 1.1 Xref: archiver1.google.com comp.lang.ada:7188 Date: 2004-04-16T01:40:01-04:00 List-Id: Wojtek Narczynski wrote: > I had in mind implementing it without the need to resort to > abstraction inversion, which I understand as -for example- > implementing semaphores over protected objects, which are implemented > over semaphores. Protected objects _may_ be implemented using semaphores, or mutexes, or counters, or any viable atomic action. But when you are programming in Ada, you have to take the tasking model, complex as it seems, as the fundamental primitive for concurrency. Protected objects were added to Ada 9X to eliminate some of the baggage that most implementations of Ada tasking carried. And to some extent they did just that. But if I need fast semaphores, I use a semaphore abstraction, then I try various implementations of the abstraction to find one which has the performance I need. If implementing a semaphore portably as a protected object works? Done. > Yes, I should probably have dropped protected type in favor of raw > semaphores. Protected objects are a very useful model for a lot of jobs that require management of concurrency. But it is a characteristic of protected objects that they manage _their_own_ concurrency, and nothing else. As long as that model fits what you are doing, great protected objects have great advantages over other techniques, such as semaphores. But there are two important points. First you _must_ as part of your analysis of the problem domain identify the objects that need to be managed. For lists and trees, two of the examples you mentioned, what usually needs to be managed is the list, or the tree: protected type List is procedure Append(E: in Element); procedure Prepend(E: in Element); ... function Is_Empty return Boolean; function Length return Natural; private ... end List; Should you expect to find a ready made implementation that meets your needs? Possibly. But you almost certainly won't find it by looking for libraries of protected objects. The usual in Ada is to provide a generic package abstraction where the protected object is hidden from the user's sight. This allows it to "reuse" the interface of a List that doesn't need protection from concurrent access. In fact, one of the changes in Ada 95 was intended to make it easier to 'hide' such a protected type in the body of a (generic) package. To go back to the example that sparked the discussion, it is not that difficult to create a protected type which protects an array of counters. It then seems natural to have both a set of atomic operations on a single counter and on a set of counters: type Index is (<>); generic package Counters is type Set is array (Index) of Boolean; type Count_Array is (Index range <>) of Integer; protected type Counters is procedure Reset(I: Index); procedure Reset(S: Set); procedure Reset; -- Zero all counters. function Count(I: Index) return Integer; function Count(S: Set) return Count_Array; function Count return Count_Array; --return a snapshot of all counts private ... end Counters; Now you may think that this is an abstraction inversion, but I don't. That is really a comment on thinking Ada. Even with Ada 83, it was _hard_ to correctly identify the 'right' objects to make the rest of the project easy, and Ada 95 has made those choices much harder. But the way it has done that is by making the object calculus much more powerful. I used to have a fully worked out example that demonstrated the issue. It was a simulation of a barber shop, with multiple chairs and barbers, customers who decided to return later if there were too many other customers waiting, and so on. But none of that was the point of the example. There was a simple elegant object-oriented solution. The insight you needed to find it though, was that the key objects were the haircuts! You could also probably come up with just as clean a model if you made the customers the key objects, but somehow _trying_ to do that leads you astray. If a parent comes into the barber shop with a child, who is the customer? Much easier to get it right, if you are thinking that a father comes into the barber shop to get _haircuts_ for both himself and his son, or only his son, or whatever. There are lots of ways to identify the potential objects in a program. Grady Booch's method of describing the problem space and underlining all the nouns is probably as good as any. But that is where the hard work begins. As in the barber shop example, there is some minimal set of objects that need to be modelled, or perhaps a better way to say that is that there is a minimal set of expensive objects that does the job. What makes objects expensive? It can be storage space, allocation and deallocation, active state, or some combination of the above. But you often don't know what cost function for the project will be at that stage of the analysis. You have to try strawmen, see which project constraints bind hardest, then start looking for opportunties to trade one resource for another. Sometimes, as in the barber shop example, there will be one elegant model which minimizes the cost in all dimensions. Other times, the engineering tradeoffs need to be decided before you can actually start coding. -- Robert I. Eachus "The terrorist enemy holds no territory, defends no population, is unconstrained by rules of warfare, and respects no law of morality. Such an enemy cannot be deterred, contained, appeased or negotiated with. It can only be destroyed--and that, ladies and gentlemen, is the business at hand." -- Dick Cheney