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=unavailable autolearn_force=no version=3.4.4 X-Received: by 10.157.2.39 with SMTP id 36mr10049924otb.69.1495397194908; Sun, 21 May 2017 13:06:34 -0700 (PDT) X-Received: by 10.157.37.213 with SMTP id q79mr415525ota.11.1495397194849; Sun, 21 May 2017 13:06:34 -0700 (PDT) Path: eternal-september.org!reader01.eternal-september.org!reader02.eternal-september.org!news.eternal-september.org!news.eternal-september.org!feeder.eternal-september.org!news.glorb.com!67no1220137itx.0!news-out.google.com!m134ni5097itb.0!nntp.google.com!67no1220131itx.0!postnews.google.com!glegroupsg2000goo.googlegroups.com!not-for-mail Newsgroups: comp.lang.ada Date: Sun, 21 May 2017 13:06:34 -0700 (PDT) In-Reply-To: Complaints-To: groups-abuse@google.com Injection-Info: glegroupsg2000goo.googlegroups.com; posting-host=173.71.201.205; posting-account=QF6XPQoAAABce2NyPxxDAaKdAkN6RgAf NNTP-Posting-Host: 173.71.201.205 References: <4a47e4cd-829c-4451-abf1-82cf60b67706@googlegroups.com> User-Agent: G2/1.0 MIME-Version: 1.0 Message-ID: <9cdf04e6-123e-4bd9-b466-77aad00d61bb@googlegroups.com> Subject: Re: Preventing private procedure visibility being made public through extension From: Jere Injection-Date: Sun, 21 May 2017 20:06:34 +0000 Content-Type: text/plain; charset="UTF-8" Xref: news.eternal-september.org comp.lang.ada:46840 Date: 2017-05-21T13:06:34-07:00 List-Id: On Sunday, May 21, 2017 at 4:44:27 AM UTC-4, Dmitry A. Kazakov wrote: > On 2017-05-21 00:51, Jere wrote: > > On Saturday, May 20, 2017 at 4:32:07 PM UTC-4, Dmitry A. Kazakov wrote: > >> On 2017-05-20 19:33, Jere wrote: > > I do know that C++ supports hiding of functions by making them private > > in the extending class. > > No. That is not possible in C++ either. A public method cannot be made > private. > > In general from the OO point of view, a method cannot be removed because > it is a property of the class and not of an individual type. It is the > contract of the class to have a method Foo. All instances of the class > must have this method. If they don't they are not instances of. Period. > > [To support method disallowing the language must support ad-hoc > superclasses, so that one could split an original class into parts to > chip the undesired operation away from one part and put the new type in > that part instead of the whole original class.] > The language supports making them private in the context of the extending classes. Take for example: class Base{ public: class Base_Param{}; void Something(Base_Param Obj){} }; class Derived : public Base { private: void Something(Base_Param Obj); }; class MoreDerived : public Derived{}; The following will not compile: void run_test(){ Base::Base_Param b; Derived d; d.Something(b); } nor will void run_test(){ Base::Base_Param b; MoreDerived m; m.Something(b); } both will fail with the error: "Something" is a private member of Derived I'm not saying it is the right design, but it is possible. You can always get around it by casting down to type Base (where the function is public), but that is an explicit action that takes intent. A user just creating a type can't use the function out of the box because, as the error indicates, it is private for Derived (and for MoreDerived by extension). > > My real issue is with how the constructors for the tagged type in > > the library are done. I want my derived type to work with the > > constructors defined in the library, which means it has to extend > > one of the types defined in the library itself. But I don't want > > clients to extend my class and use the inherited constructors from > > the base class because they'll break my extended class. > > These are not constructors proper. Maybe you meant "constructing > function". There is a huge difference. > > Anyway a constructing function being a primitive operation must work, > exactly because this is an primitive operation which gets overridden. So > works a constructor proper which is not an operation and cannot be > called explicitly and when invoked, then implicitly always with its own > type. > > What you have is neither, it is probably an operation to initialize a > part of the object. Such things are usually made private [to be used in > a public constructing function]. > > [Yes it is a huge problem for library designers that Ada does not have > constructors. Alas, there is no desire to fix that] You're right, they are not proper constructors. I haven't found anything in Ada yet that gives me that. At best they are initializers. > > I really don't like doing this. I don't like using > > access types for one. It's also doesn't feel like > > a very clean way because you have to do something > > out of the ordinary just to use the class like it was > > meant to be. > > Aggregation + delegation is a decent thing. > > If you used anonymous access you would reduce dangers of pointers to zero. > Definitely. I am also worried about someone copying the access value and holding onto it past the lifetime of the object. I try to avoid Access types when I can. I wish there was someway to actually pass a limited type as a function return that didn't involve build in place that can initialize. I just want to be able to return the limited object out temporarily to access it: Derived.Get_Base.Some_Procedure but not allow initialization when I don't intend the function to do that: Temp : Base := Derived.Get_Base; -- didn't really want to allow As it stands the only option I came up with is something kludgy like: type Derived_Public is tagged limited record Parent : Base_Type; end record; -- This is the workhorse type type Derived is new Derived_Public with private; -- This type is purely for constructor like procedures type Derived_With_Constructors is new Derived with private; procedure Constructing_Procedure (Obj : in out Derived_With_Constructors); Then people extending it just have to do: type More_Derived is new Derived with private; private type More_Derived is new Derived_With_Constructors with null record; That way, extenders don't publicly provide the Constructor procedures, but have access to them privately. Additionally, I get the Base type via composition so it's procedures won't stomp on Derived types and I can still use it in the library. There's probably a better way, but that is what I came up with. I don't like it though. > > The actual use case is Gnoga. All of the constructors > > (the Create procedures) require parent to be of type > > Gnoga.Gui.Base.Base_Type'Class, but I really want my > > Dialog_Type constructor to only accept parents of type > > Gnoga.Gui.Window.Window_Type'Class. But it also has > > to publicly extend Gnoga.Gui.Base.Base_Type > > (or I use Gnoga.Gui.View.View_Base_Type) so that > > other controls can create themselves in it. This > > opens my type and types that extend it to being > > thrashed by calls to Create_From_HTML and so on. > > Similar to your suggestion, I can override them and > > raise an exception...it just feels clunky. > > Believe other methods I know and have tried, e.g. involving generics, > are far worse. That's been my experience as well. > > I was just hoping for something better from a static checking > > perspective. There was a discussion in the Gnoga mailing > > list if you are wanting more concrete examples. I was just > > simplifying it for here to see if there was a language > > defined way to get what I needed statically. It sounds like > > there isn't. > > GUI is one of classic examples where multiple dispatch is required. It > is a fact of reality which cannot be worked around without compromising > something (no pun intended (:-)). > Thanks for the responses!