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.3 required=5.0 tests=BAYES_00, REPLYTO_WITHOUT_TO_CC autolearn=no autolearn_force=no version=3.4.4 Path: eternal-september.org!reader01.eternal-september.org!reader02.eternal-september.org!news.eternal-september.org!news.eternal-september.org!news.eternal-september.org!feeder.eternal-september.org!aioe.org!.POSTED!not-for-mail From: "Dmitry A. Kazakov" Newsgroups: comp.lang.ada Subject: Re: System.Address to Access to function/procedure conversion Date: Sun, 28 Jul 2013 22:03:02 +0200 Organization: cbb software GmbH Message-ID: <1egtr1bzjiupj$.1e2lqozcsmcve$.dlg@40tude.net> References: <15i0rfwzpj7cy$.ob5l4ffr5iqa$.dlg@40tude.net> Reply-To: mailbox@dmitry-kazakov.de NNTP-Posting-Host: q/ev1P9zCVSwu+vpMGX5Tw.user.speranza.aioe.org Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit X-Complaints-To: abuse@aioe.org User-Agent: 40tude_Dialog/2.0.15.1 X-Notice: Filtered by postfilter v. 0.8.2 Xref: news.eternal-september.org comp.lang.ada:16585 Date: 2013-07-28T22:03:02+02:00 List-Id: On Sun, 28 Jul 2013 19:05:44 +0000 (UTC), Tarek Ghaleb wrote: > On 2013-07-28, Dmitry A. Kazakov wrote: >> If you pass anything to C you should better keep it under C convention, >> even if you are certain that C does not touch it. You should pass an >> access-to-procedure/function to C and get it back. The access type will >> have pragma Convention (C, ... set. You don't need address here. E.g. > > I agree completely. Using C convention is the way to do it. But is it > *possible* to call a function using its address? (even if not a such a > great idea) > > But let me explain how this question came about: > > I've been experimenting with writing a thick binding for FLTK for a > couple of days now, just exploring the idea (which deserves a thread > by itself, since it would be interesting to get some > feedback). Anyway, one thing I started working on was callbacks, If I > use C convention the user of the binding will also have to declare his > procedure using C convention. For example (simplified) > > procedure Cb_Button; > pragma Convention (C, Cb_Button); -- This is required I guess > > and then later register the callback with > > Btn.Callback(Cb_Button'Access); > > But if I remove > > pragma Conversion (C, Cb_Button); > > I get > > ...: subprogram "Cb_Button" has wrong convention > ...: does not match convention of access type > > But I don't want the user to worry about using pragma Convention for > every defined callback procedure or think in terms of interfacing with > C (or in FLTK's case C++). Ideally, Callback() is not the actual > imported callback() but it takes Ada friendly parameters and does any > type conversions needed then calls the imported callback() function. I > thought maybe it works like above but without the convention line and > then Callback() would send the Address instead of the Access to the > actual callback(). But maybe there is a better way to do it. Usually C bindings pass an internal procedure of C convention. The user provided callback is called from there. From my POV it is too low level for good bindings. I prefer primitive operations of a tagged type instead of using a raw subprogram. E.g. an interface with the operation Clicked passed to button's On_Click. type Button_Interface is limited interface; procedure Clicked (Handler : in out Button_Interface; Issuer : Widget'Class) is abstract; type Button is ... procedure On_Click (Widget : in out Button; Handler : not null access Button_Interface'Class); -- [*] Normally C library call takes an additional parameter void* passed as a "User_Data" argument etc. Almost all C libraries provide such user data arguments. This is a way to marshal parameters to the C callback from where you call an Ada subprogram or dispatch. Depending on what is the recipient of the callback you choose the strategy of marshaling data through void*. A typical way for a widget library is that when you connect to a signal emitted by a widget, a reference counted object is allocated by the C library. The library deletes the object when the signal gets disconnected or when the widget is destroyed. This object is directly or indirectly pointed by the User_Data argument. There are various issues when which object gets deallocated, which is not simple stuff, but almost always necessary because user parameters never fit into single void* argument. When no user data argument is supported, you would use so-called "trampolines", which is of course quite nasty stuff. ------------- * You would like to wrap Button_Interface into a smart pointer object and use the latter in On_Click. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de