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=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit Path: g2news2.google.com!news2.google.com!newsfeed2.dallas1.level3.net!news.level3.com!newsfeed-00.mathworks.com!nntp.TheWorld.com!not-for-mail From: Robert A Duff Newsgroups: comp.lang.ada Subject: Re: Issue with GNAT GPL 2009 and GtkAda Date: Sat, 27 Jun 2009 13:04:47 -0400 Organization: The World Public Access UNIX, Brookline, MA Message-ID: References: <4A414EBB.8060204@free.fr> <1avd65rn49abv$.krcxo2gdzb16$.dlg@40tude.net> <4a43c9ce$0$420$426a74cc@news.free.fr> <4a44ae4e$0$6295$4f793bc4@news.tdc.fi> NNTP-Posting-Host: shell01.theworld.com Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: pcls6.std.com 1246122287 23564 192.74.137.71 (27 Jun 2009 17:04:47 GMT) X-Complaints-To: abuse@TheWorld.com NNTP-Posting-Date: Sat, 27 Jun 2009 17:04:47 +0000 (UTC) User-Agent: Gnus/5.1008 (Gnus v5.10.8) Emacs/21.3 (irix) Cancel-Lock: sha1:gAbHb2PB9BHP8vhZmvM3OrGxvUE= Xref: g2news2.google.com comp.lang.ada:6672 Date: 2009-06-27T13:04:47-04:00 List-Id: Stephen Leake writes: > "Randy Brukardt" writes: > >>>Niklas Holsti" wrote in message >>>news:4a44ae4e$0$6295$4f793bc4@news.tdc.fi... >> I think he means that the accessibility level of a parameter is that of a >> local object, ... Yes, the accessibility level of a formal parameter is like a local nested inside the procedure. This is true for tagged and untagged. >...as it *might* have been passed by copy. Not for tagged -- those are always passed by reference. > Well, I had forgotten that tagged types are by reference, so I meant > it might _actually_ be passed by copy. But apparently the compiler > isn't taking advantage of the fact that tagged types are by reference, > and is taking the more conservative view that it might be passed by copy. The compiler is just doing what the language rules require. Note that "must be passed by reference" does not imply "we could allow 'Access". Consider: type T_Ref is access all T; Global : T_Ref; procedure P (X : in out T) is -- Suppose T is tagged. begin Global := X'Access; -- Illegal! end P; procedure Q (...) is Local : aliased T; begin P (Local); end Q; After calling Q, Global is a dangling pointer. The language design rule is: If you do anything that _might_ create a dangling pointer, you have to use 'Unchecked_Access (and take care). The original example is similar to this, except the error is caught at run time, because you have an access parameter. Dynamic accessibility levels are a mistake, in my opinion! >> (There are no special rules here for tagged types.) So when you pass >> it to an access parameter, you get local accessibility and any >> attempt to use it with a named access type is going to fail a >> run-time accessibility check (raising Program_Error). > > Now I'm confused. Here's the relevant code: > > package Bug is > > -- Base interface > type Listener is interface; > type Listener_Ref is access all Listener'Class; > procedure Process (L : in out Listener) is abstract; > > -- Base class > type Base is tagged null record; > type Base_Ref is access all Base'Class; > procedure Foreach (B : access Base; I : Integer); > > -- Derived class > type Derived is new Base and Listener with null record; > type Derived_Ref is access all Derived'Class; > overriding procedure Process (D : in out Derived); > > procedure Main; > > end Bug; > -------------------------------------------------------------------------- > with Ada.Text_IO; > package body Bug is > > procedure Foreach (B : access Base; I : Integer) is > BB : Base_Ref; > begin > Ada.Text_IO.Put_Line ("Foreach" & Integer'Image (I)); > BB := B.all'Access; -- Line that fails > end Foreach; > > procedure Process (D : in out Derived) is > begin > Ada.Text_IO.Put_Line ("Process"); > D.Foreach (2); The accessibility level of D is "nested inside Process", so that information is passed to Foreach at run time. (Note that there's an implicit D'Access here.) Foreach then tries to make a value of type Base_Ref point to it, which fails at run time. This is necessary because you might put: Some_Global := BB; in Foreach, which would create a dangling pointer. If you know you're not going to do that, you can use 'Unchecked_Access. I don't see any compiler bug, here. > end Process; > > procedure Main is > G_Derived : constant Derived_Ref := new Derived; > G_Listener : constant Listener_Ref := Listener_Ref (G_Derived); > begin > Ada.Text_IO.Put_Line ("Main"); > G_Derived.Foreach (1); -- This one works > G_Listener.Process; -- This one fails > end Main; > > end Bug; > > The problem seems to be that the call in Main: > > G_Listener.Process; > > is passing a object (of a tagged type) to an "in out" parameter to Process. > > Then the body of Process does 'Access on that parameter. > > I had thought that part of the reason tagged types were by reference > was to allow this to work. It allows 'Access to work if the resulting access type is nested. It allows 'Unchecked_Access to work. > I gather you are saying that's not true, or at least the actual rules > did not achieve this desire. The actual history is that during Ada 9X, the design team proposed to allow "aliased" on parameters. Reviewers didn't like that, partly because "aliased" was seen as dangerous, and partly because the language was getting too big and complicated. So we took it out. But then after working many examples, we realized that you really need aliased parameters sometimes, especially in the case of tagged types. So we decided that all tagged parameters are aliased, and if you need aliased parameters for an untagged type, you just make it tagged even though you didn't want to. This was acceptable to reviewers, because it doesn't involve syntax, and many people view "additional syntax" as a bigger language change than "additional rules". In my view, this makes the language _more_ complicated, and if "aliased" is dangerous, surely implicit aliased is even more so. Allowing explicitly aliased parameters would lead to a simpler rule about which names denote an aliased object: 1. If the declaration of X says "aliased", then the name "X" denotes an aliased object. 2. For any X, X.all denotes an aliased object (it has to, because the whole point of "aliased" is that it means "you can have access values pointing to it" -- the fact that X points to X.all implies X.all must be aliased). But this wouldn't necessary change the accessibility rules -- you still can't take 'Access of a local and return a global pointer. >> The only way that we could have done better would be to pass an >> accessibility level with every tagged parameter. That seems like way too >> much overhead. > > I see. So the rules are more conservative than they could be, leading > to programmer surprises like this one. No, I don't think they're overly conservative -- see my dangling pointer example above. Well, of course compile-time checks are always conservative (see halting problem!). The only way to be less conservative would be to do more checks at run time, which is heading in the wrong direction. > Except that I'm not clear how accessiblity information is passed now. > Since it's a runtime check, it seems the accessiblity level must be > stored with the access object somehow; what is the extra overhead you > are talking about? In most compilers, the accessibility level is represented as an integer, and this integer is passed as an extra implicit parameter whenever you have an access parameter. So your Foreach procedure really has three parameters: B, I, and the accessibility level of B.all. Except that the extra parameter is not used if the Convention is some foreign language like C, because obviously that would mess things up. >> You can use 'Unchecked_Access to get around the accessibility check, of >> course, but if it would have failed, there is a chance that you will have >> done something that would actually create a dangling pointer. > > Right. I really appreciate the compiler telling me how to avoid > possible dangling pointers. > > So far, I've managed to write code that follows the Ada rules (without > Unchecked_Access), and still does what I want. So the current Ada > rules work for me :). > >> The aliased parameters that we're looking to add to Ada will mitigate this >> problem somewhat, but only a little. > > Which Ada Issue is this in? > > I tried searching at http://www.ada-auth.org/search-ai05s.html, but I > with Firefox only get a blank screen in response. MS Internet > Explorer gives a results page. But there are lots of results for > 'aliased parameter', and none for '"aliased parameter"'. > > Ah; searching the index page for 'aliased' finds AI05-0142, which > seems to be it. Yup. > 3.10.2 26.f > Note that for objects of a by-reference type, it is not an > error for a programmer to take advantage of the fact that > such objects are passed by reference. ... This is just saying that if you say "Formal_Param := ...;", the actual param will be modified immediately. So, for example, if you then raise an exception, the actual will have been modified, and you can see that after handling the exception in the caller. If it were a by-copy type, then you know the actual will NOT have been modified. And for other types, you don't know -- it MIGHT have been modified. > I can see why this is complicated :) It is indeed. C is much simpler in this area, because everything is aliased, and you can create dangling pointers willy-nilly. (Well, almost everything is aliased.) - Bob