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 autolearn=unavailable autolearn_force=no version=3.4.4 Path: buffer2.nntp.dca1.giganews.com!border2.nntp.dca1.giganews.com!nntp.giganews.com!usenet.blueworldhosting.com!feeder01.blueworldhosting.com!news.swapon.de!fu-berlin.de!uni-berlin.de!individual.net!not-for-mail From: Niklas Holsti Newsgroups: comp.lang.ada Subject: Re: A bad counterintuitive behaviour of Ada about OO Date: Wed, 06 Aug 2014 00:51:18 +0300 Organization: Tidorum Ltd Message-ID: References: Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-Trace: individual.net +0for1SvxVN7GB2jwP//6AxHic1vv3XaQiCJ3bCoioYHUyUleA Cancel-Lock: sha1:ZbupIa5OCUOuN3HbVeNeGaxosEU= User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:24.0) Gecko/20100101 Thunderbird/24.6.0 In-Reply-To: Xref: number.nntp.dca.giganews.com comp.lang.ada:188169 Date: 2014-08-06T00:51:18+03:00 List-Id: On 14-08-06 00:06 , Victor Porton wrote: > Simon Wright wrote: > >> Victor Porton writes: >> >>> http://freesoft.portonvictor.org/binaries/ada-obj-test.tar.gz >>> >>> contains a tiny Ada program which prints 0 despite intuition suggests >>> that it should print 123, because it just copies (using Adjust) an object >>> holding 123. >>> >>> In this program Handle_Type models some handle provided by an external >>> API, where 0 is an undefined handle. Base_Object is a tagged record which >>> holds a handle inside itself and can copy or destroy the handle >>> automatically (as Base_Object is a controlled object). >>> >>> Example_Record is a derived type of Base_Object which imitates a behavior >>> of a simple library which operates over some handles. For example, in >>> this example copying a handle preserves it unchanged. >>> >>> This tiny program was created by me as a model of my real Ada bindings >>> for Raptor C library, which produces a wrong behavior. >>> >>> Why Ada behaves in this counter-intuitive way? >>> >>> What should I do in similar situations when developing real Ada software? >> >> I think what is happening is that in >> >> function From_Handle(Handle: Handle_Type) return Base_Object is >> begin >> return (Ada.Finalization.Controlled with Handle=>Handle); >> end; >> >> the aggregate is created and copied to the function's result as a >> Base_Object, so that when >> >> procedure Adjust(Object: in out Base_Object) is >> begin >> if Object.Handle /= 0 then >> Object.Handle := Copy_Handle(Base_Object'Class(Object), >> Object.Handle); >> end if; >> end; >> >> is called during the copy, >> >> function Copy_Handle(Object: Base_Object; Handle: Handle_Type) return >> Handle_Type is begin >> return 0; >> end; >> >> returns 0, as you've seen. >> >> >> (1) If all you wanted to do was copy the Handle over, you don't need to >> do anything, because that's the default behaviour (i.e., copies the >> bits). >> >> (2) Normally, From_Handle wouldn't be inherited, so you'd have had to >> write your own; because Example_Object has a null extension, it can be >> inherited. > > I've added in example_record.ads: > > function From_Handle(Handle: Handle_Type) return Example_Object; > > and in example_record.adb: > > function From_Handle(Handle: Handle_Type) return Example_Object is > begin > return (Base_Object'(From_Handle(Handle)) with null record); > end; > > It prints "0" not as it was before. (I assume the "not" above is a mistake, and you mean that it prints "0" just as before.) That happens because in your new From_Handle for Example_Object, the part Base_Object'(From_Handle(Handle)) returns an object of type Base_Object, which is then assigned into the parent part of the extension aggregate, and this assignment operation invokes the Adjust operation for Base_Object, which invokes Copy_Handle for Base_Object, which returns a zero handle. > What to do? I write a real software project and need to make a decision what > to do in this situation. Alternatives: 1. Write a sensible Copy_Handle for Base_Object (preferred solution), or 2. make Example_Record a child package of Handled_Record, which makes the internal structure of Base_Object visible, and lets you write function From_Handle(Handle: Handle_Type) return Example_Object is begin return (Ada.Finalization.Controlled with Handle => Handle); end; and therefore lets you create Example_Objects without going through a Base_Object and its handle-destroying Copy_Handle. By the way, Dmitry's advice not to use re-dispatching is his personal opinion, shared by some people on comp.lang.ada but not by me; you should consider the pros and cons yourself. Re-dispatching is what happens in your Adjust operation when you convert the Object to Base_Type'Class and then invoke Copy_Handle. The conversion forces the call to be a dispatching call. Without conversion, the call is statically bound to the Copy_Handle of Base_Object. Re-dispatching plays no role in your problem. The problem is that by making Base_Object private, and Example_Record not a child of Handled_Record, you have made it impossible to create an Example_Object without first creating a Base_Object and therefore invoking the Adjust and Copy_Handle for Base_Object. -- Niklas Holsti Tidorum Ltd niklas holsti tidorum fi . @ .