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.9 required=5.0 tests=BAYES_00,FORGED_GMAIL_RCVD, FREEMAIL_FROM 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!postnews.google.com!d55g2000hsg.googlegroups.com!not-for-mail From: Maciej Sobczak Newsgroups: comp.lang.ada Subject: Re: Inherited Methods and such Date: Sun, 23 Sep 2007 13:36:45 -0700 Organization: http://groups.google.com Message-ID: <1190579805.451187.71140@d55g2000hsg.googlegroups.com> 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> NNTP-Posting-Host: 85.3.228.131 Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" X-Trace: posting.google.com 1190579805 27466 127.0.0.1 (23 Sep 2007 20:36:45 GMT) X-Complaints-To: groups-abuse@google.com NNTP-Posting-Date: Sun, 23 Sep 2007 20:36:45 +0000 (UTC) In-Reply-To: <1mw3qju08q8uj.sgzht7ld9ydc$.dlg@40tude.net> User-Agent: G2/1.0 X-HTTP-UserAgent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6,gzip(gfe),gzip(gfe) Complaints-To: groups-abuse@google.com Injection-Info: d55g2000hsg.googlegroups.com; posting-host=85.3.228.131; posting-account=ps2QrAMAAAA6_jCuRt2JEIpn5Otqf_w0 Xref: g2news2.google.com comp.lang.ada:2102 Date: 2007-09-23T13:36:45-07:00 List-Id: 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. > > The point is that in the constructor's body the components (fields) > > are already constructed > > Yes this is the point. > > > (the initializer list handles this) and this > > fact makes it safe to use these fields. > > 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. Surely you can leak 'this' outside and use the not-yet-existing object. Whether it is safe depends on what you already managed to do before leaking it. In general it is not safe, so don't leak 'this' from inside the constructor. > > 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. This is also why it's even more important *not* to dispatch into vacuum. > > It would not be possible if *this dispatched to Derived::f(), because > > there the Derived's fields do not yet exist. > > = the polymorphic object is not yet constructed > = the class is not yet constructed Exactly. That's what I'm writing about - the type is being built up *progressively*, not by a magic instant jump from nothing to final type. > > It is consistent - the dispatch will never trick you into using not- > > yet-constructed fields. > > That you cannot run red light on a stool does not make the latter a drive > assistant system. It's still more preferred than running red light and pretend the problem does not exist. > > 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? :-) > > But if we remove this assumption, then the inconsistency is gone. > > No. Assuming you are talking about mutating objects, it is inconsistent > with the notion of typing. You move the mess onto the client, which now > does not know what to expect from the object it deals with. No. The client doesn't even see the object before it's fully constructed, so no mess is moved onto him. The exception is when the pointer to not-yet-constructed object is leaked to the client, but this is easier to follow and constrain. Interestingly, the same problem (with leaking the pointer) exists when the types is always the final one from the start. So I don't understand why do you think this is any better. > 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? > >> Don't hurry, I can pass this as parameter: > > >> T() : A(this), B(this), C(this) {...} > > >> and enjoy all the mess. > > > Yes. You can remove this by prohibiting the use of 'this' in the > > initializer list (some compilers warn about it anyway). > > It is formally allowed, because can be useful if handled with enough > > care. > > Good intentions pave the road to hell. But returning back to the issue. > What is the type of *this the constructor of A does observe? Can you name > it? It's T. And the only thing A can legally (standard-wise) do with the given pointer is to *store it*. 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. In particular, A would need to later ask the given pointer for T's view. And again, Ada doesn't solve it, either. > > 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. > > 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 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. :-) > > 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. 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. :-) > > 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. If it does not give another object, what it gives then? A view. > > 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? > > 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. And Java, etc. The difference is that C++ does not dispatch into vacuum. > ---------------- > 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. -- Maciej Sobczak http://www.msobczak.com/