* Equivalent of dynamic_cast (downcast) for tagged types @ 2011-01-27 15:46 Maciej Sobczak 2011-01-27 16:18 ` Dmitry A. Kazakov 2011-01-27 19:33 ` Equivalent of dynamic_cast (downcast) for tagged types Adam Beneschan 0 siblings, 2 replies; 25+ messages in thread From: Maciej Sobczak @ 2011-01-27 15:46 UTC (permalink / raw) Hi, Unfortunately I need to HACK some equivalent of dynamic_cast in Ada. There is a limited tagged type T deriving from Limited_Controlled and Some_Interface as well. There is also a procedure like this: procedure Foo (X : in Some_Interface'Class); Inside Foo I would like to check if X is indeed T and if so, I would like to dynamic_cast to it and execute some operation on T. That operation is in fact declared in Some_Interface anyway, but I would like to avoid the dispatching call. I would also like to avoid any potential data copying, so access types are welcome. In C++ it would look like this: void foo(some_interface & x) { T * p = dynamic_cast<T*>(&x); if (p != NULL) { // indeed x is of type T p->do_something_for_me(); } } If you say that I should not do this because it is not good practice, then I will quickly answer that GNAT should not randomly call Adjust on my limited (!) objects. Thank you for your help. -- Maciej Sobczak * http://www.inspirel.com ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Equivalent of dynamic_cast (downcast) for tagged types 2011-01-27 15:46 Equivalent of dynamic_cast (downcast) for tagged types Maciej Sobczak @ 2011-01-27 16:18 ` Dmitry A. Kazakov 2011-01-27 17:10 ` J-P. Rosen ` (2 more replies) 2011-01-27 19:33 ` Equivalent of dynamic_cast (downcast) for tagged types Adam Beneschan 1 sibling, 3 replies; 25+ messages in thread From: Dmitry A. Kazakov @ 2011-01-27 16:18 UTC (permalink / raw) On Thu, 27 Jan 2011 07:46:33 -0800 (PST), Maciej Sobczak wrote: > Unfortunately I need to HACK some equivalent of dynamic_cast in Ada. > > There is a limited tagged type T deriving from Limited_Controlled and > Some_Interface as well. > There is also a procedure like this: > > procedure Foo (X : in Some_Interface'Class); > > Inside Foo I would like to check if X is indeed T and if so, I would > like to dynamic_cast to it and execute some operation on T. That > operation is in fact declared in Some_Interface anyway, but I would > like to avoid the dispatching call. I would also like to avoid any > potential data copying, so access types are welcome. You don't need access type, tagged types are by-reference anyway. > In C++ it would look like this: > > void foo(some_interface & x) > { > T * p = dynamic_cast<T*>(&x); > if (p != NULL) > { > // indeed x is of type T > p->do_something_for_me(); > } > } if X in T'Class then Do_Something (T (X)); -- No dispatch end if; The above is a bad idea, because X might be a descendant of T which has overridden Do_Something. So you might be looking for this if X'Tag = T'Tag then -- X is of T Do_Something (T (X)); -- No dispatch end if; > If you say that I should not do this because it is not good practice, > then I will quickly answer that GNAT should not randomly call Adjust > on my limited (!) objects. Adjust is not called on limited objects. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Equivalent of dynamic_cast (downcast) for tagged types 2011-01-27 16:18 ` Dmitry A. Kazakov @ 2011-01-27 17:10 ` J-P. Rosen 2011-01-27 17:35 ` Dmitry A. Kazakov 2011-01-27 22:49 ` Maciej Sobczak 2011-01-27 17:50 ` Georg Bauhaus 2011-01-27 22:35 ` Maciej Sobczak 2 siblings, 2 replies; 25+ messages in thread From: J-P. Rosen @ 2011-01-27 17:10 UTC (permalink / raw) Le 27/01/2011 17:18, Dmitry A. Kazakov a �crit : > if X'Tag = T'Tag then -- X is of T > Do_Something (T (X)); -- No dispatch > end if; > or if X in T then -- slightly more elegant >> If you say that I should not do this because it is not good practice, It's bad practice in C++ because it is unsafe. I see no objection in Ada, where tags are checked, and I have some pretty convincing examples of that. Admitedly, it not very OOrthodox, but OOrthodoxy has been defined by C++ people! -- --------------------------------------------------------- J-P. Rosen (rosen@adalog.fr) Adalog a d�m�nag� / Adalog has moved: 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00 ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Equivalent of dynamic_cast (downcast) for tagged types 2011-01-27 17:10 ` J-P. Rosen @ 2011-01-27 17:35 ` Dmitry A. Kazakov 2011-01-27 22:49 ` Maciej Sobczak 1 sibling, 0 replies; 25+ messages in thread From: Dmitry A. Kazakov @ 2011-01-27 17:35 UTC (permalink / raw) On Thu, 27 Jan 2011 18:10:49 +0100, J-P. Rosen wrote: > I see no objection in Ada, where tags are checked, and I have some > pretty convincing examples of that. One objection is that if tags are checked manually in an if-statement (unfortunately there is no way to use tags or equivalents in the case-statement, which is a long story to tell), there is a danger that some alternatives could remain uncovered or handled in an unexpected way. Arguably the cases, which indeed exist, should rather be addressed by multiple dispatch and extensible operations. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Equivalent of dynamic_cast (downcast) for tagged types 2011-01-27 17:10 ` J-P. Rosen 2011-01-27 17:35 ` Dmitry A. Kazakov @ 2011-01-27 22:49 ` Maciej Sobczak 1 sibling, 0 replies; 25+ messages in thread From: Maciej Sobczak @ 2011-01-27 22:49 UTC (permalink / raw) On Jan 27, 6:10 pm, "J-P. Rosen" <ro...@adalog.fr> wrote: > It's bad practice in C++ because it is unsafe. It is perfectly safe in the form that I have presented. Another version with references is also perfectly safe, as it does not even produce any null pointer value and throws an exception - which is equivalent to what Ada does. > Admitedly, it not very OOrthodox, but OOrthodoxy has been defined by C++ > people! Please note that object orientation actually works in C++, whereas it demonstrably doesn't work with GNAT (see my response to Dmitry for details) and we are talking about the time gap of some 20 years. I fully understand your opinion about C++, but in this particular case it would be very difficult to defend. OK, now ducking away to move forward my Ada project. ;-) -- Maciej Sobczak * http://www.inspirel.com ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Equivalent of dynamic_cast (downcast) for tagged types 2011-01-27 16:18 ` Dmitry A. Kazakov 2011-01-27 17:10 ` J-P. Rosen @ 2011-01-27 17:50 ` Georg Bauhaus 2011-01-27 22:35 ` Maciej Sobczak 2 siblings, 0 replies; 25+ messages in thread From: Georg Bauhaus @ 2011-01-27 17:50 UTC (permalink / raw) On 27.01.11 17:18, Dmitry A. Kazakov wrote: > The above is a bad idea, because X might be a descendant of T which has > overridden Do_Something. So you might be looking for this > > if X'Tag = T'Tag then -- X is of T > Do_Something (T (X)); -- No dispatch > end if; > The following seems to be working in Pure units, too, since it does not depend on Ada.Tags: procedure Foo (X : in out P.Some_Interface'Class) is begin declare Dynamic_Cast_X : Descendant.T renames Descendant.T(X); begin Dynamic_Cast_X.Do_Something_For_Me; end; exception when CE: Constraint_Error => -- X not of type Descendant.T ... null; end Foo; ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Equivalent of dynamic_cast (downcast) for tagged types 2011-01-27 16:18 ` Dmitry A. Kazakov 2011-01-27 17:10 ` J-P. Rosen 2011-01-27 17:50 ` Georg Bauhaus @ 2011-01-27 22:35 ` Maciej Sobczak 2011-01-28 5:07 ` Yannick Duchêne (Hibou57) ` (2 more replies) 2 siblings, 3 replies; 25+ messages in thread From: Maciej Sobczak @ 2011-01-27 22:35 UTC (permalink / raw) On Jan 27, 5:18 pm, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de> wrote: > if X in T'Class then > Do_Something (T (X)); -- No dispatch > end if; > > The above is a bad idea, because X might be a descendant of T which has > overridden Do_Something. So you might be looking for this > > if X'Tag = T'Tag then -- X is of T > Do_Something (T (X)); -- No dispatch > end if; Thank you, this makes sense. > Adjust is not called on limited objects. Yeah, sure. :-D http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41845 I have submitted this bug report more than one year ago. Looks like nobody even bothered to check it. The bug submission states that Adjust is wrongly recognized as overriding, which it shouldn't be - but now I have hit something more interesting. I got an exception from a place where a regular dispatching operation on some class-wide type was done. After some debugging and analysis the exception appeared to come from s-finroo.adb:45, from System.Finalization_Root.Adjust, which just raises Program_Error. Why the heck this Adjust was called on my Controlled_Limited type is a mystery, but that was easy to confirm: I have added the Adjust operation for my type, just as in the bug report, and instrumented it and voila - this proved that the Adjust was really *called*. But that was just the beginning. I could live with a dummy implementation of Adjust for my limited (!) type, but the real problem was with the dispatching operation that I wanted to call. This operation is a function that returns some access value - it is declared to be abstract in the base interface and implemented in my type. There is nothing between the abstract declaration and my implemetation, but my implementation is *not* called (again, instrumented), but somehow the result of the call is null, which leads to a disaster few lines later. Looks like GNAT generated some dummy body for the abstract function and called that instead. So, to summarise: yes, Adjust is randomly called on Controlled_Limited types and it even dispatches properly (wow!), and no, my own operations do not dispatch and instead something dummy gives me equally dummy results. This happens in GNAT GPL 2010, but not in older compilers. It is really demotivating to see that object orientation in its basic form still doesn't work in GNAT. But in addition to downcasting, there is an alternative solution which I have discovered later on, although have not yet tested. The idea is if I know the actual type (T) in the procedure that accepts base interface, then apparently I'm working with a closed set of types, which is actually true. So instead of relying on class-wide types and dispatching in this particular place I will add another version of the same operation that accepts T and operates on it. A bit of code duplication, but with a chance to work around this not-so- funny GNAT bug. -- Maciej Sobczak * http://www.inspirel.com ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Equivalent of dynamic_cast (downcast) for tagged types 2011-01-27 22:35 ` Maciej Sobczak @ 2011-01-28 5:07 ` Yannick Duchêne (Hibou57) 2011-01-28 9:16 ` Dmitry A. Kazakov 2011-01-28 15:13 ` Maciej Sobczak 2 siblings, 0 replies; 25+ messages in thread From: Yannick Duchêne (Hibou57) @ 2011-01-28 5:07 UTC (permalink / raw) Le Thu, 27 Jan 2011 23:35:28 +0100, Maciej Sobczak <see.my.homepage@gmail.com> a écrit: > http://gcc.gnu.org/bugzilla/show_bug.cgi?id=41845 > > I have submitted this bug report more than one year ago. Looks like > nobody even bothered to check it. Not a bug to me, while I agree this is not expected: this is “not portable” instead. However, according to the Ada reference (somewhere at the beginning I remember), a compiler with specific added capabilities, must 1) inform about this none-standard feature 2) provide an option to run the compiler in strict standard mode. I read it two or three years ago, and I suppose this apply to standard packages too (it was about overall compiler requirements to be OK to be said “an Ada compiler”). But this was not your main topic :p -- Si les chats miaulent et font autant de vocalises bizarres, c’est pas pour les chiens. “I am fluent in ASCII” [Warren 2010] ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Equivalent of dynamic_cast (downcast) for tagged types 2011-01-27 22:35 ` Maciej Sobczak 2011-01-28 5:07 ` Yannick Duchêne (Hibou57) @ 2011-01-28 9:16 ` Dmitry A. Kazakov 2011-01-28 13:11 ` AdaMagica 2011-01-28 16:44 ` Adam Beneschan 2011-01-28 15:13 ` Maciej Sobczak 2 siblings, 2 replies; 25+ messages in thread From: Dmitry A. Kazakov @ 2011-01-28 9:16 UTC (permalink / raw) On Thu, 27 Jan 2011 14:35:28 -0800 (PST), Maciej Sobczak wrote: > I have submitted this bug report more than one year ago. Looks like > nobody even bothered to check it. Well, I am not a language lawyer to tell if the behavior (public overriding of a private primitive operation) is legal. > The bug submission states that Adjust is wrongly recognized as > overriding, which it shouldn't be - but now I have hit something more > interesting. It must be overriding because Adjust is a primitive operation. Whether the compiler should allow it to become publicly declared as an overriding is another question. This is a general language design problem, also reappearing in multiple inheritance. Until addressed it will pop up in different places on different occasions. > Why > the heck this Adjust was called on my Controlled_Limited type is a > mystery, but that was easy to confirm: I have added the Adjust > operation for my type, just as in the bug report, and instrumented it > and voila - this proved that the Adjust was really *called*. Maybe the implementation is using the private operation internally. Once you have overridden it, you broke the thing. I agree that the problem must be addressed, by handling MI-like cases properly. But it is a long story. Another long story is that constructor, destructor, ":=" must be built-in primitive operations without Initialize, Finalize, Adjust kludges. AdaCore would not come to the idea of providing Adjust for limited types if there were proper constructors. > But in addition to downcasting, there is an alternative solution which > I have discovered later on, although have not yet tested. > The idea is if I know the actual type (T) in the procedure that > accepts base interface, then apparently I'm working with a closed set > of types, which is actually true. So instead of relying on class-wide > types and dispatching in this particular place I will add another > version of the same operation that accepts T and operates on it. BTW, this is another language design issue. What you want here is dispatching to a narrower class rather than to the leaf. I know no OO language which has this. Arguably many cases of downcast could be eliminated if the application would not forced either to dispatch "prematurely," or not to dispatch at all. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Equivalent of dynamic_cast (downcast) for tagged types 2011-01-28 9:16 ` Dmitry A. Kazakov @ 2011-01-28 13:11 ` AdaMagica 2011-01-28 14:13 ` Dmitry A. Kazakov 2011-01-28 16:44 ` Adam Beneschan 1 sibling, 1 reply; 25+ messages in thread From: AdaMagica @ 2011-01-28 13:11 UTC (permalink / raw) On 28 Jan., 10:16, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de> wrote: > On Thu, 27 Jan 2011 14:35:28 -0800 (PST), Maciej Sobczak wrote: > > I have submitted this bug report more than one year ago. Looks like > > nobody even bothered to check it. > > Well, I am not a language lawyer to tell if the behavior (public overriding > of a private primitive operation) is legal. > > > The bug submission states that Adjust is wrongly recognized as > > overriding, which it shouldn't be - but now I have hit something more > > interesting. > > It must be overriding because Adjust is a primitive operation. Whether the > compiler should allow it to become publicly declared as an overriding is > another question. The public specification of Ada.Finalization.Limited_Controlled has no Adjust operation, so there is no primitive operation with that name which you can override, full stop. It's irrelevant if there is some internal one deeply burrowed in the compiler's implementation. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Equivalent of dynamic_cast (downcast) for tagged types 2011-01-28 13:11 ` AdaMagica @ 2011-01-28 14:13 ` Dmitry A. Kazakov 2011-01-28 23:51 ` Randy Brukardt 0 siblings, 1 reply; 25+ messages in thread From: Dmitry A. Kazakov @ 2011-01-28 14:13 UTC (permalink / raw) On Fri, 28 Jan 2011 05:11:16 -0800 (PST), AdaMagica wrote: > On 28 Jan., 10:16, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de> > wrote: >> On Thu, 27 Jan 2011 14:35:28 -0800 (PST), Maciej Sobczak wrote: >>> I have submitted this bug report more than one year ago. Looks like >>> nobody even bothered to check it. >> >> Well, I am not a language lawyer to tell if the behavior (public overriding >> of a private primitive operation) is legal. >> >>> The bug submission states that Adjust is wrongly recognized as >>> overriding, which it shouldn't be - but now I have hit something more >>> interesting. >> >> It must be overriding because Adjust is a primitive operation. Whether the >> compiler should allow it to become publicly declared as an overriding is >> another question. > > The public specification of Ada.Finalization.Limited_Controlled has no > Adjust operation, so there is no primitive operation with that name > which you can override, full stop. It has no *visible* primitive operation. > It's irrelevant if there is some > internal one deeply burrowed in the compiler's implementation. Unfortunately it leaks out. Consider this: package P is type T is tagged private; private type T is tagged null record; procedure Foo (X : in out T); end P; with P; package Q is type S is new P.T with null record; procedure Foo (X : in out S); end Q; with Q; package P.R is type U is new Q.S with null record; procedure Bar (Object : in out U'Class); end P.R; package body P.R is procedure Bar (Object : in out U'Class) is begin Foo (Object); -- Which Foo is called here? Is there one or two? end Bar; end P.R; This problem can also be observed with components. E.g. P.T may have a component Baz, declared privately. Q.S may have "another" Baz declared publicly. P.R.U faces a name conflict which must be resolved in some of two possible ways: "overloading" vs. "overriding." -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Equivalent of dynamic_cast (downcast) for tagged types 2011-01-28 14:13 ` Dmitry A. Kazakov @ 2011-01-28 23:51 ` Randy Brukardt 2011-01-29 0:55 ` Adam Beneschan 0 siblings, 1 reply; 25+ messages in thread From: Randy Brukardt @ 2011-01-28 23:51 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:joz7ejpgeda0$.etbrqjysvoke$.dlg@40tude.net... > On Fri, 28 Jan 2011 05:11:16 -0800 (PST), AdaMagica wrote: > >> On 28 Jan., 10:16, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de> >> wrote: >>> On Thu, 27 Jan 2011 14:35:28 -0800 (PST), Maciej Sobczak wrote: >>>> I have submitted this bug report more than one year ago. Looks like >>>> nobody even bothered to check it. >>> >>> Well, I am not a language lawyer to tell if the behavior (public >>> overriding >>> of a private primitive operation) is legal. >>> >>>> The bug submission states that Adjust is wrongly recognized as >>>> overriding, which it shouldn't be - but now I have hit something more >>>> interesting. >>> >>> It must be overriding because Adjust is a primitive operation. Whether >>> the >>> compiler should allow it to become publicly declared as an overriding is >>> another question. >> >> The public specification of Ada.Finalization.Limited_Controlled has no >> Adjust operation, so there is no primitive operation with that name >> which you can override, full stop. > > It has no *visible* primitive operation. > >> It's irrelevant if there is some >> internal one deeply burrowed in the compiler's implementation. > > Unfortunately it leaks out. Consider this: > > package P is > type T is tagged private; > private > type T is tagged null record; > procedure Foo (X : in out T); > end P; > > with P; > package Q is > type S is new P.T with null record; > procedure Foo (X : in out S); > end Q; > > with Q; > package P.R is > type U is new Q.S with null record; > procedure Bar (Object : in out U'Class); > end P.R; > > package body P.R is > procedure Bar (Object : in out U'Class) is > begin > Foo (Object); -- Which Foo is called here? Is there one or two? > end Bar; > end P.R; > > This problem can also be observed with components. E.g. P.T may have a > component Baz, declared privately. Q.S may have "another" Baz declared > publicly. P.R.U faces a name conflict which must be resolved in some of > two > possible ways: "overloading" vs. "overriding." In both of these of these cases, there are two operations (no overriding happens). Either one of the Foos is invisible (in which case you get the visible one), or the program is illegal because it is ambiguous. The same happens for the components, with the exception that the type extension is illegal if there is anywhere in the program where two components with the same name could be visible. (That's necessary because they're not overloadable.) That's what the *language* says; any particular compiler may have bugs in this area. For instance, Janus/Ada has an invariant that all component names must be unique. That means an attempt to declare an extension like the one in this example will always fail, even when the hidden components never would be visible. That's wrong, and needs to get fixed someday, but is not much of a priority (the bug is pervasive - the invariant simply is wrong, but virtually all of the component processing code -- designed for Ada 83 -- depends on it, so the fix is very expensive, the bug is rare in real code, and often when it happens the type would have been illegal anyway). Randy. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Equivalent of dynamic_cast (downcast) for tagged types 2011-01-28 23:51 ` Randy Brukardt @ 2011-01-29 0:55 ` Adam Beneschan 0 siblings, 0 replies; 25+ messages in thread From: Adam Beneschan @ 2011-01-29 0:55 UTC (permalink / raw) On Jan 28, 3:51 pm, "Randy Brukardt" <ra...@rrsoftware.com> wrote: > In both of these of these cases, there are two operations (no overriding > happens). Either one of the Foos is invisible (in which case you get the > visible one), or the program is illegal because it is ambiguous. Technically, I don't think you can get an ambiguous program from two subprograms with the same name and same profile. Either one overrides the other, as you say; or, by 8.3(12.2/2), all of them will be hidden from all visibility, and then none of the Foos is visible. Although I guess that really isn't that much different from calling it "ambiguous". -- Adam ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Equivalent of dynamic_cast (downcast) for tagged types 2011-01-28 9:16 ` Dmitry A. Kazakov 2011-01-28 13:11 ` AdaMagica @ 2011-01-28 16:44 ` Adam Beneschan 2011-01-28 17:21 ` Dmitry A. Kazakov 2011-01-28 17:33 ` Adam Beneschan 1 sibling, 2 replies; 25+ messages in thread From: Adam Beneschan @ 2011-01-28 16:44 UTC (permalink / raw) On Jan 28, 1:16 am, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de> wrote: > On Thu, 27 Jan 2011 14:35:28 -0800 (PST), Maciej Sobczak wrote: > > I have submitted this bug report more than one year ago. Looks like > > nobody even bothered to check it. > > Well, I am not a language lawyer to tell if the behavior (public overriding > of a private primitive operation) is legal. > > > The bug submission states that Adjust is wrongly recognized as > > overriding, which it shouldn't be - but now I have hit something more > > interesting. > > It must be overriding because Adjust is a primitive operation. Wrong. I can't find the language rule right now, but I'm certain that if a tagged type T has a primitive operation Op declared in the private part, and another package declares a type extension of T and declares its own operation Op with the same profile, in a place where the first Op is not visible, then the new Op is a **new** operation that has no connection with the Op in the private part of the first package. This is what I would expect, since the private part of a package isn't supposed to have any semantic effect on places that can't see the private part. Here's an example: package Pak1 is type T1 is tagged null record; procedure Op1 (X : in out T1); procedure Test (Param : in out T1'Class); private procedure Op2 (X : in out T1); end Pak1; with Ada.Text_IO; use Text_IO; package body Pak1 is procedure Op1 (X : in out T1) is begin Put_Line ("in Pak1.Op1"); end Op1; procedure Op2 (X : in out T1) is begin Put_Line ("in Pak1.Op2"); end Op2; procedure Test (Param : in out T1'Class) is begin Op1 (Param); Op2 (Param); end Test; end Pak1; with Pak1; use Pak1; package Pak2 is type T2 is new T1 with null record; --overriding ILLEGAL! procedure Op2 (X : in out T2); end Pak2; with Ada.Text_IO; use Ada.Text_IO; package body Pak2 is procedure Op2 (X : in out T2) is begin Put_Line ("in Pak2.Op2"); end Op2; end Pak2; with Pak1; with Pak2; procedure Test87 is Y : Pak2.T2; begin Pak1.Test (Y); end Test87; The Op2 defined in Pak2 has no connection with the Op2 defined in the private part of Pak1. It is not overriding. And if Pak1.Op2 is called as a dispatching operation, it will **not** dispatch to Pak2.Op2, which is basically a new operation. I compiled this with GNAT and got Pak1.Op1 Pak1.Op2 as expected. (If you comment out the "private" keyword in Pak1, the second line becomes Pak2.Op2.) Furthermore, if the "overriding" line is uncommented, GNAT correctly rejects the declaration, saying the procedure does not override anything. So since it's correctly rejecting the "overriding" in this case, but not rejecting "overriding" on an Adjust operation of a type derived from Limited_Controlled, there's definitely something amiss in the compiler. My guess is that the compiler handles (Limited_)Controlled specially and thus doesn't quite go through the same path that it goes through in my example. But it's definitely a compiler bug, not a portability issue. -- Adam ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Equivalent of dynamic_cast (downcast) for tagged types 2011-01-28 16:44 ` Adam Beneschan @ 2011-01-28 17:21 ` Dmitry A. Kazakov 2011-01-29 0:12 ` Randy Brukardt 2011-01-28 17:33 ` Adam Beneschan 1 sibling, 1 reply; 25+ messages in thread From: Dmitry A. Kazakov @ 2011-01-28 17:21 UTC (permalink / raw) On Fri, 28 Jan 2011 08:44:08 -0800 (PST), Adam Beneschan wrote: > On Jan 28, 1:16�am, "Dmitry A. Kazakov" <mail...@dmitry-kazakov.de> > wrote: >> It must be overriding because Adjust is a primitive operation. > > Wrong. [information hiding rationale skipped] Yes, it is wrong (language design). The operation is primitive even if invisible in *some* contexts. It means that there might exist other contexts where two operations would conflict. Furthermore, Ada designers tried (and expectedly failed) to ensure that "multiple inheritance" always override. This goal is inconsistent with the information hiding principle, as you have just pointed out. Now, the can of worms is open and the worms are crawling far and wide. P.S. Some silly rules exist to alleviate the mess. Like the rule that an interface cannot be implemented privately. That does not help. Multiple inheritance issues must be addressed properly. There is no other way. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Equivalent of dynamic_cast (downcast) for tagged types 2011-01-28 17:21 ` Dmitry A. Kazakov @ 2011-01-29 0:12 ` Randy Brukardt 2011-01-29 8:47 ` Dmitry A. Kazakov 0 siblings, 1 reply; 25+ messages in thread From: Randy Brukardt @ 2011-01-29 0:12 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:1phnecgw6ckgv.1vm12emlufu5b.dlg@40tude.net... ... > Yes, it is wrong (language design). The operation is primitive even if > invisible in *some* contexts. It means that there might exist other > contexts where two operations would conflict. Furthermore, Ada designers > tried (and expectedly failed) to ensure that "multiple inheritance" always > override. I have no idea as to what you are talking about here. The inheritance rules haven't changed significantly since Ada 95 (there is a tweak in Ada 2012 which will help alievate this problem when it is unintentional). And multiple inheritance has nothing whatsoever to do with it. IMHO, MI is a large cannon whose primary purpose is to blow off limbs. :-) Don't do it. Remember that a lot more goes into what is overriding than just the names of operations; it also depends on the profiles and visibility. Just thinking about names always gets you into trouble when thinking about Ada. And, regardless of whether there is a language design flaw, there is no chance that this would change. It would break too much existing code. Moreover, I think that what you are talking about is actively harmful. Claw, for instance, uses the current rules to have implementation operations that are dispatching, but that clients cannot override in any circumstances. (If they did, Claw would likely fall over in a heap, causing a debugging and support nightmare.) Randy. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Equivalent of dynamic_cast (downcast) for tagged types 2011-01-29 0:12 ` Randy Brukardt @ 2011-01-29 8:47 ` Dmitry A. Kazakov 0 siblings, 0 replies; 25+ messages in thread From: Dmitry A. Kazakov @ 2011-01-29 8:47 UTC (permalink / raw) On Fri, 28 Jan 2011 18:12:20 -0600, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:1phnecgw6ckgv.1vm12emlufu5b.dlg@40tude.net... > ... >> Yes, it is wrong (language design). The operation is primitive even if >> invisible in *some* contexts. It means that there might exist other >> contexts where two operations would conflict. Furthermore, Ada designers >> tried (and expectedly failed) to ensure that "multiple inheritance" always >> override. > > I have no idea as to what you are talking about here. I mean that the issues, MI is customary accused of, are common and unavoidable with or without MI. > IMHO, MI is a > large cannon whose primary purpose is to blow off limbs. Nope, MI is an important software development tool for refactoring and reuse. My current project's size could be reduced in a third, if Ada had MI. > Remember that a lot more goes into what is overriding than just the names of > operations; it also depends on the profiles and visibility. But the core issue is always same: the choice between overloading vs. overriding. > And, regardless of whether there is a language design flaw, there is no > chance that this would change. It would break too much existing code. I don't think so, because the means to control the choice are just absent. Clearly there should be some syntax additions to specify the behavior. So far the only one is the keyword "overriding." Also there must be means to resolve unavoidable conflicts. Each overloaded item should have a unique name. Furthermore, the primitive operations should have names (presently the names of their type-specific instances are used in an ambiguous manner). > Moreover, I think that what you are talking about is actively harmful. Claw, > for instance, uses the current rules to have implementation operations that > are dispatching, but that clients cannot override in any circumstances. (If > they did, Claw would likely fall over in a heap, causing a debugging and > support nightmare.) I am talking about the reality, the reality hurts, I know (:-)). BTW, I am not proposing to change the current language behavior. I want new language means to be able to *describe* this behavior explicitly and same means to describe the alternative behavior where I wanted. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Equivalent of dynamic_cast (downcast) for tagged types 2011-01-28 16:44 ` Adam Beneschan 2011-01-28 17:21 ` Dmitry A. Kazakov @ 2011-01-28 17:33 ` Adam Beneschan 1 sibling, 0 replies; 25+ messages in thread From: Adam Beneschan @ 2011-01-28 17:33 UTC (permalink / raw) On Jan 28, 8:44 am, Adam Beneschan <a...@irvine.com> wrote: > > It must be overriding because Adjust is a primitive operation. > > Wrong. > > I can't find the language rule right now, but I'm certain that if a > tagged type T has a primitive operation Op declared in the private > part, and another package declares a type extension of T and declares > its own operation Op with the same profile, in a place where the first > Op is not visible, then the new Op is a **new** operation that has no > connection with the Op in the private part of the first package. This > is what I would expect, since the private part of a package isn't > supposed to have any semantic effect on places that can't see the > private part. Some clarifications: (1) The above doesn't apply if the "another package" is a child package. Thus, in my example, if you change Pak2 to Pak1.Pak2, that changes the result, because the Op2 in Pak1.Pak2 does override an inherited operation that is implicitly declared in the private part of Pak1.Pak2 (even though the private part of Pak1.Pak2 is itself implicit; it's still there). But when the package is not a child package, the inherited operation is not declared at all, so there's no overriding. (2) I think the language rules involved are around 3.9.2(20ff); AARM 3.9.2(20.a.3/3) seems to be the most important explanation in this case. See also AI05-126. -- Adam ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Equivalent of dynamic_cast (downcast) for tagged types 2011-01-27 22:35 ` Maciej Sobczak 2011-01-28 5:07 ` Yannick Duchêne (Hibou57) 2011-01-28 9:16 ` Dmitry A. Kazakov @ 2011-01-28 15:13 ` Maciej Sobczak 2011-01-28 17:47 ` Robert A Duff 2 siblings, 1 reply; 25+ messages in thread From: Maciej Sobczak @ 2011-01-28 15:13 UTC (permalink / raw) On Jan 27, 11:35 pm, Maciej Sobczak <see.my.homep...@gmail.com> wrote: > > Adjust is not called on limited objects. > > Yeah, sure. :-D [...] I have some more news on this. Previously my observations were that: > So, to summarise: yes, Adjust is randomly called on Controlled_Limited > types and it even dispatches properly (wow!), and no, my own > operations do not dispatch and instead something dummy gives me > equally dummy results. Interesting observation #2: my operation is the *third* primitive operation of Some_Interface. Interesting observation #3: Adjust is also the *third* primitive operation of System.Finalization_Root. Hm... I have changed the order of declarations in my spec file, so that the operation in question is now the *second* one. Guess what? :-) Now Finalize is called instead of Adjust. Yes, Finalize is the second primitive operation in System.Finalization_Root. It looks like the compiler has overwritten one virtual function table with another one and since the operations have very similar signatures, what happened is that the wrong operation was executed. If anybody from AdaCore is reading this, please take the above as a hint, I believe these observations are enough to show the proper direction. > But in addition to downcasting, there is an alternative solution which > I have discovered later on, although have not yet tested. > The idea is if I know the actual type (T) in the procedure that > accepts base interface, then apparently I'm working with a closed set > of types, which is actually true. So instead of relying on class-wide > types and dispatching in this particular place I will add another > version of the same operation that accepts T and operates on it. It works. I will stick to this solution instead of "if X in T then ..." as it is fully static instead of dynamic and it offers a better granularity for later editing - I will just remove that additional operation without touching the original one when the GNAT bug is fixed. Thanks to everybody who offered solution to my original problem. -- Maciej Sobczak * http://www.inspirel.com ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Equivalent of dynamic_cast (downcast) for tagged types 2011-01-28 15:13 ` Maciej Sobczak @ 2011-01-28 17:47 ` Robert A Duff 2011-01-28 22:04 ` Maciej Sobczak 0 siblings, 1 reply; 25+ messages in thread From: Robert A Duff @ 2011-01-28 17:47 UTC (permalink / raw) Maciej Sobczak <see.my.homepage@gmail.com> writes: > If anybody from AdaCore is reading this, please take the above as a > hint, I believe these observations are enough to show the proper > direction. Sorry, but AdaCore does not take bug reports from comp.lang.ada. AdaCore does accept bug reports from the general public, and fixes them eventually (if they turn out to be real bugs, which is often not the case!), but of course this work has lower priority than work for paying customers. There seems to be a fairly easy workaround in your case: Don't declare an Adjust procedure on limited controlled types. (I didn't read your bugzilla report; I'm just going by what you said in this thread.) - Bob ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Equivalent of dynamic_cast (downcast) for tagged types 2011-01-28 17:47 ` Robert A Duff @ 2011-01-28 22:04 ` Maciej Sobczak 2011-01-30 20:22 ` Stephen Leake 0 siblings, 1 reply; 25+ messages in thread From: Maciej Sobczak @ 2011-01-28 22:04 UTC (permalink / raw) On Jan 28, 6:47 pm, Robert A Duff <bobd...@shell01.TheWorld.com> wrote: > Sorry, but AdaCore does not take bug reports from comp.lang.ada. I knew this will pop up. :-) You see - if this happened to me, it might as well happen in the future to anybody else, including their Most Valuable Customer (tm) and that future might be next year or next week. Silently calling the wrong operation is not something that I would like to see in a critical system and I can imagine that the Most Valuable Customer (tm) can get really pissed if this happens. It is therefore in the best interest of AdaCore to have the fix ready *before* that time, so they can prove their excellent support by reacting instantly. Seems like a good strategy to me. I don't expect AdaCore to ship updated GPL version out of their calendar just because I wrote some rant on comp.lang.ada. Far from it - I anyway appreciate that I get something for free as in free beer. But if they are proactive in their care about their own business, they should do the homework before this problem hits them the hard way. In other words: I, as a person, can have very low priority for them. But the BUG in their product must have a very high priority, no matter who is reporting it. Last but not least: the only reason why I don't submit a separate bugzilla report for this is that I do not have the minimal reproducible test case. But I'm willing to provide all necessary information and assistance on request. > There seems to be a fairly easy workaround in your case: > Don't declare an Adjust procedure on limited controlled > types. I didn't - and that's why I got Program_Error from the Adjust operation that is in s_finroo.adb:45. I have declared Adjust for my own type only as part of my investigations and in fact this allowed me to gather some interesting observations that I described already. BTW - I *never* declare Adjust in normal code, because I never use non- limited Controlled types. -- Maciej Sobczak * http://www.inspirel.com ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Equivalent of dynamic_cast (downcast) for tagged types 2011-01-28 22:04 ` Maciej Sobczak @ 2011-01-30 20:22 ` Stephen Leake 2011-01-31 9:04 ` AdaCore, user community and communication channels Maciej Sobczak 0 siblings, 1 reply; 25+ messages in thread From: Stephen Leake @ 2011-01-30 20:22 UTC (permalink / raw) Maciej Sobczak <see.my.homepage@gmail.com> writes: > On Jan 28, 6:47 pm, Robert A Duff <bobd...@shell01.TheWorld.com> > wrote: > >> Sorry, but AdaCore does not take bug reports from comp.lang.ada. > > I knew this will pop up. :-) > > You see - if this happened to me, it might as well happen in the > future to anybody else, including their Most Valuable Customer (tm) > and that future might be next year or next week. This is true. > Silently calling the wrong operation is not something that I would > like to see in a critical system and I can imagine that the Most > Valuable Customer (tm) can get really pissed if this happens. It is > therefore in the best interest of AdaCore to have the fix ready > *before* that time, so they can prove their excellent support by > reacting instantly. Seems like a good strategy to me. Yes. But the point is, how are they to become aware of the bug? Think of all the places bugs might be mentioned; here, on your personal blog, on some university student mailing list, on a Debian bug list, etc. AdaCore cannot possibly monitor all possible places bugs might be mentioned. What they can do is provide one place to report bugs to them, and make that as easy to use as possible. That is sending an email to report@gnat.com. Why have you not done that? I can think of one reason; this is not mentioned on libre.adacore.com/libre. Searching for "report bug" there turned up a reference to reporting bugs in GtkAda, but not for other AdaCore tools. So I'm reporting a bug in the website, via an unrecognized channel; chance of success? > Last but not least: the only reason why I don't submit a separate > bugzilla report for this is that I do not have the minimal > reproducible test case. But I'm willing to provide all necessary > information and assistance on request. AdaCore does not take bugs from bugzilla either. -- -- Stephe ^ permalink raw reply [flat|nested] 25+ messages in thread
* AdaCore, user community and communication channels 2011-01-30 20:22 ` Stephen Leake @ 2011-01-31 9:04 ` Maciej Sobczak 2011-01-31 10:42 ` Georg Bauhaus 0 siblings, 1 reply; 25+ messages in thread From: Maciej Sobczak @ 2011-01-31 9:04 UTC (permalink / raw) On Jan 30, 9:22 pm, Stephen Leake <stephen_le...@stephe-leake.org> wrote: > Yes. But the point is, how are they to become aware of the bug? This is very simple: AdaCore is the leading provider of Ada-related products and comp.lang.ada is the most active social website where Ada is being discussed - and, please fasten your seatbelt, where their next generation of customers is growing up. If AdaCore does not lurk here, then there is either something terribly wrong with them or with this newsgroup - ie. at least one of them has serious identity issues. > AdaCore cannot possibly monitor all possible places bugs might be > mentioned. Of course. They have to set up some borders, where to stop. This border also defines the "relevancy" of any given forum. > What they can do is provide one place to report bugs to them, and make > that as easy to use as possible. That is sending an email to > rep...@gnat.com. > > Why have you not done that? Because, as already mentioned, I don't have the reduced test case. Please also note that I have described my problem as a follow-up to my original question in this thread, in order to explain what happened, why I wanted to bypass the dynamic dispatch and because I consider the whole to be technically interesting in general. It was not supposed to be a bug-report and I have never claimed it is intended to be. But... > So I'm reporting a bug in the website, via an unrecognized channel; > chance of success? ... as already said, if comp.lang.ada is "an unrecognized channel", there is something wrong. > AdaCore does not take bugs from bugzilla either. Then they will take them from their Most Valuable Customer (tm). Next year or next week. I'm really fine with that and I think I have already done enough on my side. -- Maciej Sobczak * http://www.inspirel.com ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: AdaCore, user community and communication channels 2011-01-31 9:04 ` AdaCore, user community and communication channels Maciej Sobczak @ 2011-01-31 10:42 ` Georg Bauhaus 0 siblings, 0 replies; 25+ messages in thread From: Georg Bauhaus @ 2011-01-31 10:42 UTC (permalink / raw) On 31.01.11 10:04, Maciej Sobczak wrote: > On Jan 30, 9:22 pm, Stephen Leake <stephen_le...@stephe-leake.org> > wrote: > >> Yes. But the point is, how are they to become aware of the bug? > > This is very simple: AdaCore is the leading provider of Ada-related > products and comp.lang.ada is the most active social website where Ada > is being discussed - and, please fasten your seatbelt, where their > next generation of customers is growing up. If AdaCore does not lurk > here, then there is either something terribly wrong with them or with > this newsgroup - ie. at least one of them has serious identity issues. Perhaps another means of nurturing future Ada markets should be added to the picture: the GAP contracts might be creating win-win situations, without the need for programming students (and AdaCore staff) to spend time in a public news group. I'll also speculate that not all types of programmer personalities would wish to present themselves in public fora. If said sets of next generation customers are perceived to be relatively large, there is only one conclusion considering comp.lang.ada: AdaCore staff stopping by would be enough, and should be preferred to spending work hours here. At least when seen from the perspective of a marketing agent who compares Utility(Resource => GAP) and Utility(Resource => comp.lang.ada). ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Equivalent of dynamic_cast (downcast) for tagged types 2011-01-27 15:46 Equivalent of dynamic_cast (downcast) for tagged types Maciej Sobczak 2011-01-27 16:18 ` Dmitry A. Kazakov @ 2011-01-27 19:33 ` Adam Beneschan 1 sibling, 0 replies; 25+ messages in thread From: Adam Beneschan @ 2011-01-27 19:33 UTC (permalink / raw) On Jan 27, 7:46 am, Maciej Sobczak <see.my.homep...@gmail.com> wrote: > Hi, > > Unfortunately I need to HACK some equivalent of dynamic_cast in Ada. > > There is a limited tagged type T deriving from Limited_Controlled and > Some_Interface as well. > There is also a procedure like this: > > procedure Foo (X : in Some_Interface'Class); > > Inside Foo I would like to check if X is indeed T if X in T > and if so, I would > like to dynamic_cast to it and execute some operation on T. then Execute_Some_Operation_On (T(X)); end if; Wonderful, no? In Ada you get to write pretty much what you were thinking of doing. The C++ equivalent is quite elegant, if you consider the number of ugly punctuation characters and cryptically- named built-in identifiers to be a measure of elegance. -- Adam ^ permalink raw reply [flat|nested] 25+ messages in thread
end of thread, other threads:[~2011-01-31 10:42 UTC | newest] Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2011-01-27 15:46 Equivalent of dynamic_cast (downcast) for tagged types Maciej Sobczak 2011-01-27 16:18 ` Dmitry A. Kazakov 2011-01-27 17:10 ` J-P. Rosen 2011-01-27 17:35 ` Dmitry A. Kazakov 2011-01-27 22:49 ` Maciej Sobczak 2011-01-27 17:50 ` Georg Bauhaus 2011-01-27 22:35 ` Maciej Sobczak 2011-01-28 5:07 ` Yannick Duchêne (Hibou57) 2011-01-28 9:16 ` Dmitry A. Kazakov 2011-01-28 13:11 ` AdaMagica 2011-01-28 14:13 ` Dmitry A. Kazakov 2011-01-28 23:51 ` Randy Brukardt 2011-01-29 0:55 ` Adam Beneschan 2011-01-28 16:44 ` Adam Beneschan 2011-01-28 17:21 ` Dmitry A. Kazakov 2011-01-29 0:12 ` Randy Brukardt 2011-01-29 8:47 ` Dmitry A. Kazakov 2011-01-28 17:33 ` Adam Beneschan 2011-01-28 15:13 ` Maciej Sobczak 2011-01-28 17:47 ` Robert A Duff 2011-01-28 22:04 ` Maciej Sobczak 2011-01-30 20:22 ` Stephen Leake 2011-01-31 9:04 ` AdaCore, user community and communication channels Maciej Sobczak 2011-01-31 10:42 ` Georg Bauhaus 2011-01-27 19:33 ` Equivalent of dynamic_cast (downcast) for tagged types Adam Beneschan
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox