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: a07f3367d7,73cb216d191f0fef X-Google-Attributes: gida07f3367d7,public,usenet X-Google-NewGroupId: yes X-Google-Language: ENGLISH,ASCII-7-bit X-Received: by 10.180.106.232 with SMTP id gx8mr653430wib.2.1365596606582; Wed, 10 Apr 2013 05:23:26 -0700 (PDT) Path: ex12ni34309wid.1!nntp.google.com!feeder1.cambriumusenet.nl!feed.tweaknews.nl!85.12.40.130.MISMATCH!xlned.com!feeder1.xlned.com!border2.nntp.ams.giganews.com!nntp.giganews.com!de-l.enfer-du-nord.net!feeder2.enfer-du-nord.net!feeder1.enfer-du-nord.net!gegeweb.org!aioe.org!.POSTED!not-for-mail From: "Dmitry A. Kazakov" Newsgroups: comp.lang.ada Subject: Re: Is this expected behavior or not Date: Thu, 4 Apr 2013 10:26:42 +0200 Organization: cbb software GmbH Message-ID: <1fmcdkj58brky.bjedt0pr39cd$.dlg@40tude.net> References: <2qwq2cdeuvhu$.qtnb8zyhuob9$.dlg@40tude.net> <1u72u7h5j4jg3$.wlxmaltyzqik.dlg@40tude.net> <1gnmajx2fdjju.1bo28xwmzt1nr.dlg@40tude.net> <3gv2jwc95otm.pl2aahsh9ox8.dlg@40tude.net> <1gkxiwepaxvtt$.u3ly33rbwthf.dlg@40tude.net> Reply-To: mailbox@dmitry-kazakov.de NNTP-Posting-Host: FbOMkhMtVLVmu7IwBnt1tw.user.speranza.aioe.org Mime-Version: 1.0 X-Complaints-To: abuse@aioe.org User-Agent: 40tude_Dialog/2.0.15.1 X-Notice: Filtered by postfilter v. 0.8.2 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Date: 2013-04-04T10:26:42+02:00 List-Id: On Wed, 3 Apr 2013 19:04:24 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" wrote in message > news:1gkxiwepaxvtt$.u3ly33rbwthf.dlg@40tude.net... >> If you have more than one controlled argument/result of the same type, >> that makes it a multi-method. The natural consequence of this is that all >> possible combinations of types from the hierarchy are specific bodies to >> inherit/override. In Ada 95 only the bodies when all types are same can be >> overridden. Statically the compiler prevents calls to mixed types bodies, >> but they nevertheless exist and can be reached through dispatch. In that >> case it works as if the body were "rase Constraint_Error." This hack won't >> work for &, =, <, <= etc. Those require almost all combinations to work. > > I see where you are coming from, but I don't agree with any of it on a > fundamental level: mixing types in operations is virtually always an error > (either a real mistake or a design error). How is it an error to compare String and Wide_String? > I don't believe that these use cases are at all common. I don't recall any > such cases in Claw, for example, which uses Ada 95 inheritance extensively. That is because GUI does not require dyadic operations at all. There are few cases for MD though. E.g. procedure Render (Surface : in out Device_Type; Shape : Geometric_Type); And of course: procedure Set_Text (Control : Edit_Box; Text : Root_String_Type); >> The only pattern that sometimes works is recursive cascaded dispatch. That >> is when you make one argument controlled and another class-wide. > > Gosh, that's what I was talking from the beginning. It works only with dyadic operations, procedures or else functions returning an alien type. >> I used it for "=" and "<" multi-method operations of the target type >> hierarchy of >> smart pointers. I needed this to be able to have ordered collections of >> smart pointers to such objects when pointers are ordered by the objects >> they point to. It is extremely tedious, involves recursive calls and >> explicit tag comparisons for ancestry. It won't work with for operations >> like &, which has two arguments and the result. > > You don't want mixed operations in cases like "&", ever. Non-starter for strings. > It simply doesn't > make any sense from a resolution prespective. You want to fix resolution by > introducing a set of very complex preference rules. Actually I want these rules defined by the programmer. And resolution is only the issue with the operations returning the type, e.g. literals. One cannot have both covariant result factories and multi-method operations. If I ran the circus I would try to define rules that would prohibit declaration of potentially conflicting operations, like: type T is ...; -- Untagged class function Generator return T; function "=" (L, R : T) return Boolean; This should be an error unless preference rules defined by the programmer for T. > Based on our experience > with much easier changes (like resolving routines inherited from > interfaces), the likelihood of getting that right is about 0% - it would > take years of detailed work to create a model that both worked and did not > introduce incompatibilities. Yes, it is a serious work - a type system overhaul. You cannot fix it without careful design. >>> In any case, that >>> extends the problem of creating extensions -- it would be so diifficult >>> and time-consuming that it almost never would be done. >> >> It is not an extension, it meant to be the same interface and a completely >> different representation. Extension is the same interface and extended >> representation. > > Interfaces alone are worthless. The only thing that makes inheritance worth > the effort is the ability to share implementations. Implementation /= representations. You can share class-wide operations and inherit primitive operations without sharing the representation. >> Anyway, the point is, that the compiler shall inherit a body IF AND ONLY IF >> it knows that this would be safe to do. That is the following cases: >> >> 1. Any operation when the representation is same >> >> 2. In-operation when the representation is extension or constraint >> >> 3. Out-operation when the representation is generalization (lifted >> constraint) [Ada does not have this, as an example consider extension of >> an enumeration type] >> >> 4. User-defined conversion defined, programmer's responsibility [Ada does >> not have this] >> >> On top of that come pre- and post-conditions which may in their turn >> disallow inheritance of the body. > > Besides being incompatible, ? I merely explained why Ada 95 design choice was right [#2]. > I suspect that this would just be too complex > for the average Ada user to understand. It need not to be understood. The programmer will be asked to override operation or else to make type abstract, just as Ada 95 did. >>>>> The only way to implement those is >>>>> via some sort of dispatching, and the need poisons the possibility of >>>>> omitting tags, even for "specific" operations. >>>> >>>> I don't understand where you get this. The model is exactly the model of >>>> tagged types, but without specific objects required to keep the tag. The >>>> only thing it influences is view conversions between T and T'Class. >>>> Nothing else is changed. >>> >>> When you dispatch to an inherited routine, you directly call that routine >>> with the operands view converted (which cannot make copies in the general >>> case). >> >> For by-copy types dispatching call will be copy-in / copy-out. The >> representation of T'Class is tag + value. Tag is stripped, value passed >> through. >> >> For by-reference untagged types dispatching call will pass the reference. >> The representation of T'Class is tag + pointer. Tag is stripped, reference >> passed through. > > What about the majority of types which are neither By-Copy nor By-Reference? > Such types allow the compiler to chose how they're passed, and that would > seem to be a huge problem for this model. Not at all, the compiler is free to choose, so it must. [I don't consider schizophrenic compilers choosing one way and doing in another. That does not work with any model.] > You'd have to forcibly specify one > or the other for all types, which is certain to be incompatible with > existing implementations. The compiler vendor simply follows the choice he made before. > It strikes me that the model of stripping tags means that type conversion of > an object to a class-wide type would effectively change the tag (if the > routine was inherited or called by a conversion of an operand). Yes, re-dispatch is a broken thing. Don't do it, because it is ambiguous in general case when objects do not have an identity. By-copy scalar types are such things. There is nothing which could distinguish Integer 13 from Long_Integer 13 except the context. Once you dispatched that information is lost. There is no way back. > That would > mean that the behavior of such a conversion would be very different for an > untagged type and for a tagged type. Not different. It is just so that tagged types per design have type identity. Other types simply don't have it. For an untagged by-reference type an identity still could be added through the Rosen's trick: type T is limited record Self : access T'Class := T'Unchecked_Access; ... end record; >>>>> That >>>>> forces the representation to be compatible. You could change that for >>>>> by-copy types (although that would have run-time compatibility issues >>>>> for controlled objects), >>>> >>>> Controlled objects are tagged, hence no change here. >>> >>> A component is an object; I'm talking about untagged objects with >>> controlled components here. >> >> No change either. If a by-copy object passed by value has a controlled >> component that component is copied-in and out using Adjust and >> Finalization. > > That's the problem. If that is done in existing code, you have an > incompatibility (because the same code does something different now). Why? If that type is by-copy then this is how it must work already. If it is by-reference then nothing changes either. >>>>> but you can't change that for types that have no copy >>>>> operation (like tasks and protected objects). So how to do you >>>>> implement >>>>> them? Array of task is an untagged type, too, and it certainly should >>>>> be >>>>> able to use 'Class. >>>> >>>> Sure. T'Class will be a referential object when T is untagged >>>> by-reference >>>> type. It will consist of the type tag and a *pointer* to the specific >>>> object (not much different from 4.1.5), and from view conversions ether, >>>> though formally a new object. >>>> >>>> When T is by-copy, T'Class is the type tag + a copy of T. >>> >>> Wow! And this is supposed to be a *simplification*??? :-) >> >> Yes. It is much simpler to view tagged types as a special case [definite >> representation constraint] of a more general model that encompasses all >> types. > > A more general model that is many times more complex than the existing > model. What exactly is being simplified? You will have all strings in one hierarchy. All characters in another. All integer types in third. Tagged types described using a footnote. >>>>>> The whole idea is not to inherit irrelevant representations! >>>>> >>>>> I don't see the problem here; if Root_String is an abstract tagged >>>>> type, >>>> >>>> Java interfaces will not work for characters/strings. No need even to >>>> try it. >>> >>> Java interfaces will not work for anything. No need to even try. :-) And >>> who's talking about Java, anyway? >> >> You want strings hierarchy of one level depth. That won't work. > > I don't even know what you mean by "one level depth", but I've already > prototyped such a string type and it works fine -- better than the existing > types. You want to derive each string type straight from Root_String. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de