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 X-Google-Thread: 103376,dbcfe2b0a74da57e X-Google-Attributes: gid103376,public,usenet X-Google-Language: ENGLISH,ASCII-7-bit Path: g2news2.google.com!news4.google.com!feeder1-2.proxad.net!proxad.net!feeder2-2.proxad.net!newsfeed.arcor.de!newsspool1.arcor-online.net!news.arcor.de.POSTED!not-for-mail From: "Dmitry A. Kazakov" Subject: Re: Inherited Methods and such Newsgroups: comp.lang.ada User-Agent: 40tude_Dialog/2.0.15.1 MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Reply-To: mailbox@dmitry-kazakov.de Organization: cbb software GmbH References: <1190125656.071013.303640@22g2000hsm.googlegroups.com> <1ds7l1l7oeyrx.1cpsvrpkikour.dlg@40tude.net> <1190147965.676457.123000@d55g2000hsg.googlegroups.com> <1co37tau98gct.axsglmqh0xu9$.dlg@40tude.net> <1190213376.707449.146640@g4g2000hsf.googlegroups.com> <1fl2wnziigxfd.1fjbag2hh8sbc$.dlg@40tude.net> <1190239986.762473.204290@k79g2000hse.googlegroups.com> <1rw45b3rmvmcr$.1df4wst5oknbl$.dlg@40tude.net> <1190296353.624737.150940@y42g2000hsy.googlegroups.com> <11m13st1f92kf$.m8s6y8mc8ebk.dlg@40tude.net> <1190321119.206313.65290@57g2000hsv.googlegroups.com> <1190408526.100291.265040@50g2000hsm.googlegroups.com> <9ukf2wtqjs0q$.iuijmal4x56b$.dlg@40tude.net> <1190497995.498679.119190@19g2000hsx.googlegroups.com> <1mw3qju08q8uj.sgzht7ld9ydc$.dlg@40tude.net> <1190579805.451187.71140@d55g2000hsg.googlegroups.com> Date: Mon, 24 Sep 2007 11:32:23 +0200 Message-ID: <1i8ksr774bjbj.vpmnx3c0i9qz.dlg@40tude.net> NNTP-Posting-Date: 24 Sep 2007 11:26:50 CEST NNTP-Posting-Host: 7cdc7a31.newsspool3.arcor-online.net X-Trace: DXC=R[_D]OIhIVPHigV@eW57PQMcF=Q^Z^V3X4Fo<]lROoRQ^;5]aA^R6>RS`MTh_6ckMQ[6LHn;2LCV^7enW;^6ZC`TIXm65S@:3>_N:;0cJ;KaW] X-Complaints-To: usenet-abuse@arcor.de Xref: g2news2.google.com comp.lang.ada:2107 Date: 2007-09-24T11:26:50+02:00 List-Id: On Sun, 23 Sep 2007 13:36:45 -0700, Maciej Sobczak wrote: > On 23 Wrz, 10:41, "Dmitry A. Kazakov" > wrote: > >>>> But you objected that *this is specific. You claimed that it dispatches in >>>> f(), if it does then it is of T'Class. >> >>> This concept has no meaning there. >> >> Which concept? > > T'Class. It has no meaning, because there is no possible family of > types there. There is one type T and everything dispatches to T. > Forget dynamic dispatch where you are in the constructor. Sorry, are you arguing against the concept or against C++ model (that uses this concept in an inappropriate way? (:-)) >> That is irrelevant. Relevant is whether the object is safe to use as T. > > The funny part is that formally there is no such object yet. Finally. And how is it called when something non-existing can still be used as if it were existing and, moreover, were of the type T? It is called "untyped mess." >>> This is important - you can *use* the fields, because they were >>> already constructed. >> >> A pile of fields does not make it object. Again, it is either untyped, or >> else you are talking about another type: struct {...}. You have constructed >> "struct," a predefined container type, you didn't T. > > Yes. Still, there is a lot I can do from the methods of the class, > which understand the state. These methods can even operate before the > invariants of T are fully established. After all, it's their natural > ability. No, this is incorrect. Methods are allowed to break public invariants in the course of their execution. But that by no means implies that invariants do not hold on the method's input and output. > This is also why it's even more important *not* to dispatch into > vacuum. You have a wrong impression that I wanted this. That's wrong. My position is even stricter. It is that it is inconsistent to dispatch even after having a fully constructed T. To dispatch you have to construct a polymorphic object (like T'Class), to have a specific T is only a premise of construction of T'Class. (There could be special types (like tagged types in Ada and "class" types in C++) for which construction of a polymorphic object may happen automatically. That does not mean, that it is the same object.) Note the implication: if you construct an S derived from T and have constructed only T, then T'Class is still not constructed and you cannot dispatch. Only after construction of S, you can proceed to T'Class, and after that, lo and behold, you can dispatch safely! This is why I am arguing for class-wide constructors (strictly speaking, user-defined hooks on the completion of). From there you could dispatch. >>> The inconsistency can be found >>> under the assumption that types must be invariant. >> >> Types aren't invariant. You are free to construct new types. > > That's what I'm writing about. What are we discussing, then? :-) That the type of a given object is invariant. => you can't create an object before its type => you can't destroy a type before any of its objects => you can't change the type of an object When you pass an in out object as a parameter of different (but compatible) type, the model tells that first a new object is created. Then that is passed to the subprogram. After completion the result is converted back. This is the semantic level. Whether the implementation would reuse the memory allocated for the original object is irrelevant. >> If you >> constrain the mutation scale in *any* way, and tell the client about that, >> then this would *automatically* define the true type of the object, and all >> these fake types you are talking about would be just aberrations. > > That's true. How do you compare C++ with Ada in this context? In Ada it is called T'Class. > I understand your objection that in this case (given the above > constraint) it's not T anymore, but making it formally complete would > bring more practical issues than it theoretically solves. That is another discussion. The point was about inconsistency of the model. How to repair it in C++ without separation of T and T'Class? I don't know. I strongly believe that there is no way. IMO the issue is tightly related to the naive set theory. It does not hold. > And again, Ada doesn't solve it, either. Ada does not have user-defined constructors, so it stays consistent. Though this greatly limits Ada and gives the birth to chimerical constructs like functions returning limited objects. >>> I don't get it. You can call & on the type, unless operator& is >>> private. >> >> Which type? You said that the only thing objects have for sure is their >> names. Period. No types, no operations. > > No, I didn't say that. I said that the address (name) persists while > the object moves along the constructor chain. When it comes to > operations, note that the object's type move along the known type > chain. This also allows to predict which operations are available. In > particular (in the case of constructor chain), operations never > disappear, so if you already know some of them at any given stage, you > can keep using them. Formally it would mean that the object is of the type class {T1,T2,...,Tn} where T1-Tn is the construction path. This type has the operation "address," etc. Alas, this is not what actually happens. Because, as you claimed, you can dispatch and the target of dispatch moves => it is more than just one class. It is not even a type, it is a set of. Something like { class {T1}, class {T1, T2}, class {T1, T2, T3}, ... } But the effect of all this horrible mess is equivalent to the following simpler set of types: { T1, T2, T3, ... } This is why I initially said that 1. it does not dispatch (in the simpler model); 2. the type is specific in each "constructor"; 3. the thingy is untyped because we have a set of types instead one >>> So - what about growing up? >> >> The attribute Age. > > You try to hide now. :-) > Again: Human has two subclasses: Child and Adult. > > What about growing up? The attributes do. If you want to keep it one class (human), you are forced to have a model where each client would be able to deal with either a child or an adult. So growing up humans is all about different attributes (object's values) of humans. When, you a client see a human and what to classify him/her, you ask that human about the age, make a medical examination etc. There is no other way. >>> The only way to grow up the child in Ada and C++ is to kill a child >>> and resurrect it as an adult, reshuffling all necessary references in >>> the system so that they point to the new entity. >>> Not funny. >> >> But alas real, our cells get replaced as we grow. > > As far as I know, not in heart tissue. But this is off-topic. :-) Even so, the molecules of cells are permanently replaced. Further the atoms building them fundamentally cannot be identified. There is no such thing as identity in the physical world. >>> No. dynamic_cast gives another view on the same object. It does not >>> give another object. >> >> So you want to introduce views. There are object and views of. Care to >> define a difference, in terms *types* of course? (:-)) > > View is what you have with references to objects. There is nothing to > introduce here. You did references. Is reference an object? What is the type of? > In particular, you can have *many views of different types* on *the > same object* at *the same time*. Don't try to hide it under the > carpet, it will pop up anyway. :-) To hide what? I doubt very much that we could define views in a more or less acceptable way. Because aliasing cannot be. My point is, a view is just a new object of a *new* type. >>> You talk with someone over the phone. At some point you discover that >>> it's an adult, then you agree with him (dynamic_cast) that from now on >>> you can talk like adults. It's still the same person, you just know >>> more about him. >> >> Good example. We talk over a communication protocol, which itself is an >> object. Yes, there will be another protocol instance after handshaking. Of >> course we could design the protocol level as a parameter. But then, >> firstly, that would not make it a different type, and secondly, that could >> be an unsafe design, as we could forget about the constraint and get an >> exception. > > And your point is? Mine was that dynamic_cast does not give another > object. It does. Any function returns a new object. Simple? (:-)) >>> Without this "complexity" you get real complexity with dispatching to >>> vacuum. >> >> Nope, it is crystal clear in vacuum: no class, no dispatch. Type and only >> type have to tell what's going on. > > I don't get it. If I dispatch to the type where even the fields were > not yet initialized, how I can decide what I can do? Which type should > I ask? q.e.d. You cannot consistently answer this question => the model is wrong. >>> It's >>> after the constructor finishes when the clients can use the object via >>> its public interface. From their point of view the object exists after >>> the constructor finished. From the constructor point of view, the >>> fields exist before the constructor's body is executed. Easy. >> >> = you shall not use any public interface methods from the constructor's >> body => C++ is inconsistent allowing this. > > Yes. My turn: Ada is insonsistent here as well. Ada is consistent because Initialize is not a constructor. It washes its hands: if we don't know how to do it properly, we better don't. >> ---------------- >> Just annotate types. Fields construction does struct {...}. No less, no >> more. You can access fields because struct {...} has been constructed. You >> cannot use anything from T / struct {...}, because T is not yet >> constructed. (/ denotes set subtraction). The object of struct {...} does >> exist. The object T does not. Disagree? > > I like it. Really. > Well, not really. You might leak the 'this' pointer (which would be of > type struct {...}) out of the constructor and anybody would be able to > mess with fields, which breaks encapsulation. > > Instead of struct {...} I'd prefer: > > class T_fields > { > private: > ... // all fields (or their references) go here > > friend class T; > }; > > Private fields make it safe to leak the pointer outside (it's useless > outside, so no harm in leaking it), and friend declaration allows > access from T's constructor itself and other involved methods. > Another, maybe simpler, option would be to make the struct {...} > private in T, so it could not be even leaked and no protection is then > necessary. It does not leak because the fields were exposed (by the programmer), i.e. semantically T inherits from struct{...}. It was his decision. Surely he should be able not to publicly inherit from struct, then the fields wouldn't be publicly accessible. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de