* Re: Extension of non-limited type needs limited component
@ 2002-11-15 10:47 Grein, Christoph
2002-11-15 12:12 ` Dmitry A. Kazakov
0 siblings, 1 reply; 33+ messages in thread
From: Grein, Christoph @ 2002-11-15 10:47 UTC (permalink / raw)
> >This is not SmallTalk, where you can dispatch to a method that does not
> >exist.
>
> Sure? And what about this:
>
> type A is tagged ...
> procedure Foo (L, R : A);
>
> type B is new A with ....
>
> X : A'Class := Some_A;
> Y : A'Class := Some_B;
>
> Foo (X, Y); -- Oops, dispatching to nowhere!
Either compiler catches this and does not compile.
Or during runtime, tag check is performed and will raise Constraint_Error.
No dispatching to nowhere!
^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-15 10:47 Extension of non-limited type needs limited component Grein, Christoph @ 2002-11-15 12:12 ` Dmitry A. Kazakov 2002-11-15 13:29 ` Jean-Pierre Rosen 0 siblings, 1 reply; 33+ messages in thread From: Dmitry A. Kazakov @ 2002-11-15 12:12 UTC (permalink / raw) On Fri, 15 Nov 2002 11:47:49 +0100 (MET), "Grein, Christoph" <christoph.grein@eurocopter.com> wrote: >> >This is not SmallTalk, where you can dispatch to a method that does not >> >exist. >> >> Sure? And what about this: >> >> type A is tagged ... >> procedure Foo (L, R : A); >> >> type B is new A with .... >> >> X : A'Class := Some_A; >> Y : A'Class := Some_B; >> >> Foo (X, Y); -- Oops, dispatching to nowhere! > >Either compiler catches this and does not compile. >Or during runtime, tag check is performed and will raise Constraint_Error. > >No dispatching to nowhere! Of course. Under dispatching to nowhere I just meant dispatching to a non-existing method: Foo (L : A; R: B); Both Ada and SmallTalk [AFAIK] do not crash when such thing happens. But this is not the problem. The problem is that though one could wish to detect all such and similar cases at compile time, one cannot. This does not mean that we should drop compile-time checks. [To put it clear, Ada is right, SmallTalk is wrong! (:-))] It only means that the argument, "this is not allowed, because it cannot be fully checked at compile time" is wrong. Alas, there are many damn useful things uncheckable at compile time. --- Regards, Dmitry Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-15 12:12 ` Dmitry A. Kazakov @ 2002-11-15 13:29 ` Jean-Pierre Rosen 2002-11-15 14:34 ` Dmitry A. Kazakov 2002-11-15 21:26 ` Robert A Duff 0 siblings, 2 replies; 33+ messages in thread From: Jean-Pierre Rosen @ 2002-11-15 13:29 UTC (permalink / raw) [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain, Size: 1058 bytes --] "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> a �crit dans le message news: > Both Ada and SmallTalk [AFAIK] do not crash when such thing happens. > But this is not the problem. The problem is that though one could wish > to detect all such and similar cases at compile time, one cannot. This > does not mean that we should drop compile-time checks. [To put it > clear, Ada is right, SmallTalk is wrong! (:-))] It only means that the > argument, "this is not allowed, because it cannot be fully checked at > compile time" is wrong. Alas, there are many damn useful things > uncheckable at compile time. ... with tagged types. The benefit, and drawback, of tagged types is that they allow dynamic typing, therefore requiring (isn't it surprising) dynamic checking. More flexibility, less security. If you want full compile-time checking, don't use tagged types. At least in Ada, you have a choice! -- --------------------------------------------------------- J-P. Rosen (rosen@adalog.fr) Visit Adalog's web site at http://www.adalog.fr ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-15 13:29 ` Jean-Pierre Rosen @ 2002-11-15 14:34 ` Dmitry A. Kazakov 2002-11-15 21:26 ` Robert A Duff 1 sibling, 0 replies; 33+ messages in thread From: Dmitry A. Kazakov @ 2002-11-15 14:34 UTC (permalink / raw) On Fri, 15 Nov 2002 14:29:31 +0100, "Jean-Pierre Rosen" <rosen@adalog.fr> wrote: >"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> a �crit dans le message >news: >> Both Ada and SmallTalk [AFAIK] do not crash when such thing happens. >> But this is not the problem. The problem is that though one could wish >> to detect all such and similar cases at compile time, one cannot. This >> does not mean that we should drop compile-time checks. [To put it >> clear, Ada is right, SmallTalk is wrong! (:-))] It only means that the >> argument, "this is not allowed, because it cannot be fully checked at >> compile time" is wrong. Alas, there are many damn useful things >> uncheckable at compile time. > >... with tagged types. > >The benefit, and drawback, of tagged types is that they allow dynamic >typing, therefore requiring (isn't it surprising) dynamic checking. More >flexibility, less security. If you want full compile-time checking, don't >use tagged types. You could also use a less restrictive "..., don't use class-wide objects with tags unknown at compile-time." >At least in Ada, you have a choice! Right. --- Regards, Dmitry Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-15 13:29 ` Jean-Pierre Rosen 2002-11-15 14:34 ` Dmitry A. Kazakov @ 2002-11-15 21:26 ` Robert A Duff 1 sibling, 0 replies; 33+ messages in thread From: Robert A Duff @ 2002-11-15 21:26 UTC (permalink / raw) "Jean-Pierre Rosen" <rosen@adalog.fr> writes: > The benefit, and drawback, of tagged types is that they allow dynamic > typing, therefore requiring (isn't it surprising) dynamic checking. More > flexibility, less security. If you want full compile-time checking, don't > use tagged types. Well, it's not quite that bad. Dmitry Kazakov posted the example of a procedure with 2 controlling operands. Yes, that requires a tag check. Downward conversions require a tag check. But normal dispatching on a single controlling operand (which is by far the most common case) requires no run-time check. So, for most of your code, you can freely use tagged and class-wide types, and *still* get full compile-time checking. That's the advantage of Ada (and C++ and Java) over Smalltalk (and CLOS and ...). In other words, "...don't use tagged types" is too strong. > At least in Ada, you have a choice! Yes. - Bob ^ permalink raw reply [flat|nested] 33+ messages in thread
* Extension of non-limited type needs limited component @ 2002-11-13 10:03 Mike 2002-11-13 12:06 ` Jean-Pierre Rosen 2002-11-13 14:28 ` Robert A Duff 0 siblings, 2 replies; 33+ messages in thread From: Mike @ 2002-11-13 10:03 UTC (permalink / raw) How do I extend a non-limited tagged type to add a limited component? Mike ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-13 10:03 Mike @ 2002-11-13 12:06 ` Jean-Pierre Rosen 2002-11-14 9:26 ` Mike 2002-11-13 14:28 ` Robert A Duff 1 sibling, 1 reply; 33+ messages in thread From: Jean-Pierre Rosen @ 2002-11-13 12:06 UTC (permalink / raw) [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain, Size: 585 bytes --] "Mike" <michael.jackson5@virgin.net> a �crit dans le message news: 2dbd76f3.0211130203.7d2d14fd@posting.google.com... > How do I extend a non-limited tagged type to add a limited component? > You can't. Make the original type limited. The whole hierarchy has to be limited (or not limited, excluding adding a limited element). The reason is that otherwise, you could end up trying to assign a variable with a limited component. -- --------------------------------------------------------- J-P. Rosen (rosen@adalog.fr) Visit Adalog's web site at http://www.adalog.fr ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-13 12:06 ` Jean-Pierre Rosen @ 2002-11-14 9:26 ` Mike 2002-11-14 11:43 ` David C. Hoos, Sr. ` (2 more replies) 0 siblings, 3 replies; 33+ messages in thread From: Mike @ 2002-11-14 9:26 UTC (permalink / raw) I wrote > > How do I extend a non-limited tagged type to add a limited component? Jean-Pierre Rosen replied > You can't. Make the original type limited. > The whole hierarchy has to be limited (or not limited, excluding adding a > limited element). The reason is that otherwise, you could end up trying to > assign a variable with a limited component. Unfortunately I can't make the base type limited as it is a generic gui dialog base 'class'. I understand that I would need to make the extended type limited to avoid the possible assignment to the limited component, but I cannot see why I should have to make the whole hierarchy limited. How can assignment by upcasting the extended type possibly affect the limited component? Regards, Mike ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-14 9:26 ` Mike @ 2002-11-14 11:43 ` David C. Hoos, Sr. 2002-11-14 12:33 ` Jean-Pierre Rosen 2002-11-14 23:39 ` Robert A Duff 2 siblings, 0 replies; 33+ messages in thread From: David C. Hoos, Sr. @ 2002-11-14 11:43 UTC (permalink / raw) ----- Original Message ----- From: "Mike" <michael.jackson5@virgin.net> Newsgroups: comp.lang.ada To: <comp.lang.ada@ada.eu.org> Sent: November 14, 2002 3:26 AM Subject: Re: Extension of non-limited type needs limited component > I wrote > > > > How do I extend a non-limited tagged type to add a limited component? > > Jean-Pierre Rosen replied > > > You can't. Make the original type limited. > > The whole hierarchy has to be limited (or not limited, excluding adding a > > limited element). The reason is that otherwise, you could end up trying to > > assign a variable with a limited component. > > Unfortunately I can't make the base type limited as it is a generic > gui dialog base 'class'. > > I understand that I would need to make the extended type limited to > avoid the possible assignment to the limited component, but I cannot > see why I should have to make the whole hierarchy limited. > > How can assignment by upcasting the extended type possibly affect the > limited component? > Since the purpose of "limited" is to prevent having multiple copies of the same object (e.g. an object of Ada.Text_IO.File_Type) wherein changing the state of one of the copies is changed (e.g. by closing the file in the previous example) would leave the other copy in an incorrect state, allowing limited components in a non-limited record would violate this principle. On the other hand, if multiple access objects are used to designate the same limited object, then changes to the state by reference through one of the access objects will be reflected in all of the access objects designating that limited object. Of course, the specifier of a limited type may provide a Copy procedure (e.g., with a declaration like procedure Copy (From : My_Limited_Type; To : out My_Limited_Type); In that case, the fact that use of a Copy procedure is required, rather than a simple assignment, makes the user of the type aware, that he is creating a new distinct object, not a new reference to an existing object. ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-14 9:26 ` Mike 2002-11-14 11:43 ` David C. Hoos, Sr. @ 2002-11-14 12:33 ` Jean-Pierre Rosen 2002-11-14 14:27 ` Dmitry A. Kazakov 2002-11-14 23:39 ` Robert A Duff 2 siblings, 1 reply; 33+ messages in thread From: Jean-Pierre Rosen @ 2002-11-14 12:33 UTC (permalink / raw) [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain, Size: 858 bytes --] "Mike" <michael.jackson5@virgin.net> a �crit dans le message news: 2dbd76f3.0211140126.5d233e41@posting.google.com... > How can assignment by upcasting the extended type possibly affect the > limited component? > Consider: X : T'class := Some_Dynamic_Function (1); Y : T'class := Some_Dynamic_Function (2); begin X := Y; At compile time, we know nothing about the specific type of the values in X and Y, but assuming that T is not limited, the assignment is allowed. If X and Y happen to have different tags at run time, the assignment will raise Constraint_Error, but that's all. If you were allowed to extend T with limited components, you would effectively copy the limited components! -- --------------------------------------------------------- J-P. Rosen (rosen@adalog.fr) Visit Adalog's web site at http://www.adalog.fr ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-14 12:33 ` Jean-Pierre Rosen @ 2002-11-14 14:27 ` Dmitry A. Kazakov 2002-11-14 19:25 ` Randy Brukardt 2002-11-15 0:30 ` Robert A Duff 0 siblings, 2 replies; 33+ messages in thread From: Dmitry A. Kazakov @ 2002-11-14 14:27 UTC (permalink / raw) On Thu, 14 Nov 2002 13:33:07 +0100, "Jean-Pierre Rosen" <rosen@adalog.fr> wrote: >"Mike" <michael.jackson5@virgin.net> a �crit dans le message news: >2dbd76f3.0211140126.5d233e41@posting.google.com... >> How can assignment by upcasting the extended type possibly affect the >> limited component? >> >Consider: > > X : T'class := Some_Dynamic_Function (1); > Y : T'class := Some_Dynamic_Function (2); >begin > X := Y; > >At compile time, we know nothing about the specific type of the values in X >and Y, but assuming that T is not limited, the assignment is allowed. If X >and Y happen to have different tags at run time, the assignment will raise >Constraint_Error, but that's all. > >If you were allowed to extend T with limited components, you would >effectively copy the limited components! An LSP violation to put it short. Which also raises an interesting question, whether T'Class should always inherit "non-limitness" of T. Or more generally shouldn't one have an ability to disallow primitive operations (like ":=" in case of non-limited->limited mutation)? Let we allow disallowing, then either 1. ":=" should dispatch in X:=Y to a disallowed operation, thus raise an exception and so refuse to copy the limited components. 2. ":=" is class-wide in the right parameter, then it will dispatch somewhere within its body and again an exception will happen if an attempt to copy a limited component will be made.. --- Regards, Dmitry Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-14 14:27 ` Dmitry A. Kazakov @ 2002-11-14 19:25 ` Randy Brukardt 2002-11-15 10:04 ` Dmitry A. Kazakov 2002-11-15 21:41 ` Robert A Duff 2002-11-15 0:30 ` Robert A Duff 1 sibling, 2 replies; 33+ messages in thread From: Randy Brukardt @ 2002-11-14 19:25 UTC (permalink / raw) Dmitry A. Kazakov wrote in message <3vb7tug4h99mmalcn0l5ul18cu0ui6i458@4ax.com>... >Which also raises an interesting question, whether T'Class should >always inherit "non-limitness" of T. Or more generally shouldn't one >have an ability to disallow primitive operations (like ":=" in case of >non-limited->limited mutation)? Of course, Ada has the capability to disallow ":=". It's called (drum roll) "limited". :-) This issue was discussed extensively during the Ada 95 design process. It seems like some way to disallow ":=" is needed, but we kept coming back to the point that that is what "limited" is for. We certainly don't need two notions of no ":=". >... >1. ":=" should dispatch in X:=Y to a disallowed operation, thus raise >an exception and so refuse to copy the limited components. I don't know why this wasn't chosen. It seems better on the surface. Possibly because of the desire to catch errors at compile-time rather than run-time. However, that still doesn't solve the problem that we had in Claw. What we wanted was a limited root window type with non-limited (thus assignable) controls. That is, something like: Root_Window_Type (limited controlled) Basic_Window_Type (limited) Root_Dialog_Type (limited) Modal_Dialog_Type (limited) Root_Control_Type (non-limited) Edit_Type (non-limited) Checkbox_Type (non-limited) Static_Text_Type (non-limited) [We want to be able to copy control objects because our goal was "no visible pointers required" for the interface.] This does not have the classwide assignment problem, because only Root_Control_Type has ":=", so it isn't possible to dispatch to a limited type's ":=". We ended up making the whole hierarchy non-limited, but this means implementing assignment for types for which is both a lot of work and unneeded (such as application windows). Worse, we didn't meet our "no pointers" goal, because we can't put limited objects into extentions of application windows. (So you have to use pointers to do that.) I don't recall why you are not allowed to make the extension of the limited type non-limited. (I didn't find anything in the AARM on this subject.) Randy Brukardt ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-14 19:25 ` Randy Brukardt @ 2002-11-15 10:04 ` Dmitry A. Kazakov 2002-11-15 22:09 ` Robert A Duff 2002-11-15 21:41 ` Robert A Duff 1 sibling, 1 reply; 33+ messages in thread From: Dmitry A. Kazakov @ 2002-11-15 10:04 UTC (permalink / raw) On Thu, 14 Nov 2002 13:25:13 -0600, "Randy Brukardt" <randy@rrsoftware.com> wrote: >Dmitry A. Kazakov wrote in message ><3vb7tug4h99mmalcn0l5ul18cu0ui6i458@4ax.com>... >>Which also raises an interesting question, whether T'Class should >>always inherit "non-limitness" of T. Or more generally shouldn't one >>have an ability to disallow primitive operations (like ":=" in case of >>non-limited->limited mutation)? > >Of course, Ada has the capability to disallow ":=". It's called (drum >roll) "limited". :-) > >This issue was discussed extensively during the Ada 95 design process. >It seems like some way to disallow ":=" is needed, but we kept coming >back to the point that that is what "limited" is for. In an OO language like Ada 95 is, "limited" makes little sense, because it covers only one of many useful alternatives. >We certainly don't need two notions of no ":=". But there are indeed multiple notions of ":=". Let ":=" is exposed as a normal operation. Then two arguments would give us 4 different variants [without much thinking about how useful are some of them]: procedure ":=" (Left : in out T; Right : T); procedure ":=" (Left : in out T'Class; Right : T); procedure ":=" (Left : in out T; Right : T'Class); procedure ":=" (Left : in out T'Class; Right : T'Class); Same is valid for all operations with several parameters. For instance, the predefined "=" (Left, Right : T), which cannot be disallowed with a disastrous result that a user-defined "=" (Left : T; Right : T'Class) gets overloaded with the predefined one. >>1. ":=" should dispatch in X:=Y to a disallowed operation, thus raise >>an exception and so refuse to copy the limited components. >I don't know why this wasn't chosen. It seems better on the surface. >Possibly because of the desire to catch errors at compile-time rather >than run-time. Yep, LSP again. However, nobody cares about LSP in case of X : Positive; which also shamefully violates LSP and leads to a run-time exception, should -1 happen to be assigned to X. >However, that still doesn't solve the problem that we had in Claw. What >we wanted was a limited root window type with non-limited (thus >assignable) controls. That is, something like: > > Root_Window_Type (limited controlled) > Basic_Window_Type (limited) > Root_Dialog_Type (limited) > Modal_Dialog_Type (limited) > Root_Control_Type (non-limited) > Edit_Type (non-limited) > Checkbox_Type (non-limited) > Static_Text_Type (non-limited) > >[We want to be able to copy control objects because our goal was "no >visible pointers required" for the interface.] BTW. Why do not we have constant record members in Ada? Maybe because there is no true contructors with parameters? >This does not have the classwide assignment problem, because only >Root_Control_Type has ":=", so it isn't possible to dispatch to a >limited type's ":=". > >We ended up making the whole hierarchy non-limited, but this means >implementing assignment for types for which is both a lot of work and >unneeded (such as application windows). Worse, we didn't meet our "no >pointers" goal, because we can't put limited objects into extentions of >application windows. (So you have to use pointers to do that.) This is an opposite this = defining new operations. It should be a lesser problem (for LSP). >I don't recall why you are not allowed to make the extension of the >limited type non-limited. (I didn't find anything in the AARM on this >subject.) A need to generate some predefined assignment? The whole idea of "limitness" is IMO wrong. Let's expose ":=", default constructor, copy constructor to the programmer and let he have a headache! (:-)) --- Regards, Dmitry Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-15 10:04 ` Dmitry A. Kazakov @ 2002-11-15 22:09 ` Robert A Duff 2002-11-16 12:39 ` Dmitry A. Kazakov ` (3 more replies) 0 siblings, 4 replies; 33+ messages in thread From: Robert A Duff @ 2002-11-15 22:09 UTC (permalink / raw) Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes: > In an OO language like Ada 95 is, "limited" makes little sense, > because it covers only one of many useful alternatives. But non-limited/limited does not just mean assignment allowed/disallowed. How do you propose to deal with all the other things controlled by this distinction? For example: Non-limited types can have unconstrained aliased components; limited types cannot. Limited types can have access discriminants; non-limited types cannot. Limited types can have limited components (like tasks and protected objects); non-limited types cannot. The current instance of a limited type is aliased, so you can say "T'Unchecked_Access" inside type T, to make a pointer to the current object of type T. You can't do that for non-limited. (Most) limited types are guaranteed to be passed by reference; that's not true for non-limited. A function can construct a new object of a non-limited type, and return it. You can't do that for (most) limited types. The point is that there are some things you can do for limited that you can't do for non-limited, and vice-versa, so neither is a subset of the other. Therefore, you can't derive a limited type from a non-limited type, nor vice-versa. By the way, have you read the AARM annotations that explain why we didn't allow user-defined ":=" procedures? We certainly wanted to, but we couldn't figure out how to make it work, so we invented Adjust, which is not as powerful. I'd be interested in hearing better ideas (even though it's probably too late). - Bob ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-15 22:09 ` Robert A Duff @ 2002-11-16 12:39 ` Dmitry A. Kazakov 2002-11-16 16:15 ` Robert A Duff 2002-11-17 12:26 ` Dale Stanbrough ` (2 subsequent siblings) 3 siblings, 1 reply; 33+ messages in thread From: Dmitry A. Kazakov @ 2002-11-16 12:39 UTC (permalink / raw) Robert A Duff wrote: > Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes: > >> In an OO language like Ada 95 is, "limited" makes little sense, >> because it covers only one of many useful alternatives. > > But non-limited/limited does not just mean assignment > allowed/disallowed. How do you propose to deal with all the other > things controlled by this distinction? For example: > > Non-limited types can have unconstrained aliased components; limited > types cannot. > > Limited types can have access discriminants; non-limited types > cannot. > > Limited types can have limited components (like tasks and protected > objects); non-limited types cannot. > > The current instance of a limited type is aliased, so you can say > "T'Unchecked_Access" inside type T, to make a pointer to the current > object of type T. You can't do that for non-limited. > > (Most) limited types are guaranteed to be passed by reference; > that's not true for non-limited. > > A function can construct a new object of a non-limited type, and > return it. You can't do that for (most) limited types. All that are more or less decoupled things. Why should we tie all of them under one roof? > The point is that there are some things you can do for limited that you > can't do for non-limited, and vice-versa, so neither is a subset of the > other. Therefore, you can't derive a limited type from a non-limited > type, nor vice-versa. > > By the way, have you read the AARM annotations that explain why we > didn't allow user-defined ":=" procedures? Yes, however it was some 2 years ago, so will re-read it again. > We certainly wanted to, > but we couldn't figure out how to make it work, so we invented Adjust, > which is not as powerful. I'd be interested in hearing better ideas > (even though it's probably too late). I think that Adjust maybe is just fine. The actual problem is an attempt to hide everything from the programmer. Copy+Adjust is a copy constructor, fine, but why ":=" should be *always* generated out of it? In my view there should be a way to decouple them, i.e. to get rid of the predefined ":=", and to define a new one. If a programmer does it, it is now his responsibility to ensure that the semantics of ":=" be better close to Copy+Adjust. To diminish the consequent mess with inheritance of ":=", one could say that if the right parameter is not class-wide, then it is covariant, so ":=" has to be either overridden or else disallowed in any derived type. [However, I am afraid, that to correctly deal with it one would need multiple dispatch anyway.] -- Regards, Dmitry A. Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-16 12:39 ` Dmitry A. Kazakov @ 2002-11-16 16:15 ` Robert A Duff 2002-11-17 11:14 ` Dmitry A. Kazakov 0 siblings, 1 reply; 33+ messages in thread From: Robert A Duff @ 2002-11-16 16:15 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > All that are more or less decoupled things. Why should we tie all of them ^^^^^^^^^^^^ > under one roof? Less, I'd say. ;-) They are all closely related to whether you can copy the thing. To answer my question properly, you would have to explain exactly when each of the things I mentioned should be allowed. That's not easy. No, I don't expect anybody to do all that work for an informal usenet discussion. ;-) >...[However, I am afraid, that to correctly deal with it one > would need multiple dispatch anyway.] I like the idea of multi-dispatch, but all of the languages I've seen that support it seem confusing and/or error-prone. You need a rule that makes it predictable which method(s) will be called in every case. Not just predictable in a formal sense, but predictable by mere mortal programmers -- i.e. the programmer's guess should match what the compiler actually does. And you need a way to prevent ambiguities -- cases where two different methods are "reasonable" should be forbidden, preferably at compile time. And you need a way to organize the code -- with single dispatch, you can put the "methods" with the "type" (or "class" or whatever). - Bob ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-16 16:15 ` Robert A Duff @ 2002-11-17 11:14 ` Dmitry A. Kazakov 0 siblings, 0 replies; 33+ messages in thread From: Dmitry A. Kazakov @ 2002-11-17 11:14 UTC (permalink / raw) Robert A Duff wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > >> All that are more or less decoupled things. Why should we tie all of them > ^^^^^^^^^^^^ >> under one roof? > > Less, I'd say. ;-) > > They are all closely related to whether you can copy the thing. Here we are. Why copying should be tied with: by-reference vs. not an ability to have uninitialized objects an ability to reference objects inheritance aggregation ... All this big variety of possibilities surely influence each other, but this does not mean that you can break all this into a simple: limited/non-limited. > To answer my question properly, you would have to explain exactly > when each of the things I mentioned should be allowed. I think that it would be better that the properties of an abstract type could be specified more directly. Currently we a doing it indirectly and very roughly, because the language has its own set of type properties which are not well mapped to ADT, for the programmer's point of view. To require all objects to be initialized is a damn simple thing. But to achieve this, one should make it discriminated! And then, no arrays of the type! Why all this? It is because of a wrong idea to control the program semantics. To put it very extremely, if a programmer wants to use the character sequence ":=" for his type, let him do it. It is not the language responsibility to make this ":=" semantically correct. The only thing a good safe language should do is to make the programmer aware of the consequences. For instance, require overriding of the user-defined ":=", in case of inheritance. Clarify that ":=" in declarations is not an assignment, but a copy-constructor. That ":=" will never be imlicitly used by the compiler to copy the components of the type, so if ":=" is defined, then Adjust has to be overridden, etc. > That's not > easy. No, I don't expect anybody to do all that work for an informal > usenet discussion. ;-) (:-)) >>...[However, I am afraid, that to correctly deal with it one >> would need multiple dispatch anyway.] > > I like the idea of multi-dispatch, but all of the languages I've seen > that support it seem confusing and/or error-prone. There should be a consistent solution. Otherwise the whole idea of dispatch was wrong. [I do not exclude this possibility] > You need a rule that > makes it predictable which method(s) will be called in every case. Not > just predictable in a formal sense, but predictable by mere mortal > programmers -- i.e. the programmer's guess should match what the > compiler actually does. The major problem I see is a geometric exposion of the methods to be overriden. In the case of binary operations it is three methods. If one gets overridden then all others shall be too. > And you need a way to prevent ambiguities -- > cases where two different methods are "reasonable" should be forbidden, > preferably at compile time. This could be done by a requirement of explicit overriding in all cases of potential ambiguities, but the consequence is the geometric explosion. > And you need a way to organize the code -- > with single dispatch, you can put the "methods" with the "type" (or > "class" or whatever). Yes, the freezing rules. There is practically no other solution than Ada's one: all methods to be declared before the first use. However it is not so restrictive as it might look. -- Regards, Dmitry A. Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-15 22:09 ` Robert A Duff 2002-11-16 12:39 ` Dmitry A. Kazakov @ 2002-11-17 12:26 ` Dale Stanbrough 2002-11-18 20:33 ` Randy Brukardt 2002-11-18 21:48 ` Eric 2002-11-19 14:38 ` Eric 3 siblings, 1 reply; 33+ messages in thread From: Dale Stanbrough @ 2002-11-17 12:26 UTC (permalink / raw) In article <wccbs4q8oys.fsf@shell01.TheWorld.com>, Robert A Duff <bobduff@shell01.TheWorld.com> wrote: > By the way, have you read the AARM annotations that explain why we > didn't allow user-defined ":=" procedures? We certainly wanted to, > but we couldn't figure out how to make it work, so we invented Adjust, > which is not as powerful. I'd be interested in hearing better ideas > (even though it's probably too late). It seemed to me that the main problem with with discriminants in the tagged types. Would it not have been simpler just to disallow them? Would this have allowed you to have a ":=" procedure? Dale ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-17 12:26 ` Dale Stanbrough @ 2002-11-18 20:33 ` Randy Brukardt 0 siblings, 0 replies; 33+ messages in thread From: Randy Brukardt @ 2002-11-18 20:33 UTC (permalink / raw) Dale Stanbrough wrote in message ... >In article <wccbs4q8oys.fsf@shell01.TheWorld.com>, > Robert A Duff <bobduff@shell01.TheWorld.com> wrote: > >> By the way, have you read the AARM annotations that explain why we >> didn't allow user-defined ":=" procedures? We certainly wanted to, >> but we couldn't figure out how to make it work, so we invented Adjust, >> which is not as powerful. I'd be interested in hearing better ideas >> (even though it's probably too late). > >It seemed to me that the main problem with with discriminants >in the tagged types. Would it not have been simpler just to >disallow them? Would this have allowed you to have a ":=" >procedure? No, the main problem is components of controlled types used in untagged variant records. We hardly could disallow discriminants on all records! We can't disallow components of controlled types that are discriminant-dependent, because that would be a generic contract violation. (Tagged types match generic formal private types.) Assume-the-worst here would be very incompatible. So, to get a first-class ":=", you'd have to make seriously incompatible changes to Ada 83. (Not to mention Ada 95.) That just doesn't work. To show the problem in short, assume that 'Window' is a controlled type with a user-defined ":=". type Prob (B : Boolean := True) is record case B is when True => W : Window; when False => null; end case; end record; Obj_False : Prob (False); Obj_True : Prob (True); Obj : Prob; Obj := Obj_False; -- Component W disappears in this assignment. (It is Finalized only.) Obj := Obj_True; -- Component W appears in this assignment. (It is Adjusted only.) So, what are the parameters to a user-defined ":="?? The problem is even more fun when it happens in a discriminant-dependent array. One of the nice things (from an implementability perspective) about the Adjust solution is that it composes nicely. User-defined ":=" does not seem to have this property unless disappearing components are somehow disallowed. Randy Brukardt. ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-15 22:09 ` Robert A Duff 2002-11-16 12:39 ` Dmitry A. Kazakov 2002-11-17 12:26 ` Dale Stanbrough @ 2002-11-18 21:48 ` Eric 2002-11-19 14:38 ` Eric 3 siblings, 0 replies; 33+ messages in thread From: Eric @ 2002-11-18 21:48 UTC (permalink / raw) "Robert A Duff" <bobduff@shell01.TheWorld.com> wrote in message news:wccbs4q8oys.fsf@shell01.TheWorld.com... [SNIP]> > By the way, have you read the AARM annotations that explain why we > didn't allow user-defined ":=" procedures? We certainly wanted to, > but we couldn't figure out how to make it work, so we invented Adjust, > which is not as powerful. I'd be interested in hearing better ideas > (even though it's probably too late). > > - Bob Hi, (I have reproduced the relevant annotation at the end.) The following solutions come to mind (I haven't gone through all the possible ramifications and potential problems): 1. (The example in the AARM specifically refers to mutable, unconstrained record targets.) Consider an 'operator' "<-" (which is the current Ada implemented 'move of value') to disambiguate the procedure ":=". So the present non-limited controlled implementation of procedure ":=" looks like: procedure ":="(Target : in out TYPE; Source : in TYPE) is [anonymous_object : TYPE <- Source;] begin Finalize(Target); Target <- anonymous_object; [Finalize(anonymous_object);] Adjust(Target); end ":="; Since finalization should (must) always be done before the target is overwritten, Finalize and "<-" (plus any other constraint checks) can be combined into the attribute Uncontrolled_Assign so that the above looks like: procedure ":="(Target : in out TYPE; Source : in TYPE) is [anonymous_object : TYPE <- Source;] begin Target'Uncontrolled_Assign(anonymous_object); [Finalize(anonymous_object);] Adjust(Target); end ":="; Thus: a user defined implementation of ":=" could be: procedure ":="(Target : in out TYPE; Source : in TYPE) is New_Source : TYPE [<- ...]; -- Finalized on procedure return begin -- Fiddle with New_Source based on both Target and -- Source (and constraints) Target'Uncontrolled_Assign(New_Source); -- Fiddle with Target (probably unneeded) end ":="; Note that this use of Uncontrolled_Assign would probably require a recheck of any constraints. The only problem of significance that I see is the initiation of New_Source and how to prevent an infinite loop if it is initiated (using ":=") to Source. Also, as ":=" is defaulted to call Adjust, current code would not need be rewritten. 2. Change the assignment sequence from: anonymous_object <- Source Finalize(Target) Target <-anonymous_object; Finalize(anonymous_object) Adjust(Target) To: anonymous_object <- Source other_anonymous_object <- Target Finalize(Target) Target <- anonymous_object; Finalize(anonymous_object) Adjust(Target, other_anonymous_object) -- ***** Finalize(other_anonymous_object) with Adjust taking a second 'in' argument. This would allow Adjust to make use of the original value of Target. Not as useful as the above, but I have already met code where it would be useful. Here is the annotation (reformatted from Section 7.6 of the AARM): Reason: An alternative design for user-defined assignment might involve an Assign operation instead of Adjust: procedure Assign(Target : in out Controlled; Source : in out Controlled); Or perhaps even a syntax like this: procedure ":="(Target : in out Controlled; Source : in out Controlled); Assign (or ":=") would have the responsibility of doing the copy, as well as whatever else is necessary. This would have the advantage that the Assign operation knows about both the target and the source at the same time - it would be possible to do things like reuse storage belonging to the target, for example, which Adjust cannot do. However, this sort of design would not work in the case of unconstrained discriminated variables, because there is no way to change the discriminants individually. For example: type Mutable(D : Integer := 0) is record X : Array_Of_Controlled_Things(1..D); case D is when 17 => Y : Controlled_Thing; when others => null; end D; end record; An assignment to an unconstrained variable of type Mutable can cause some of the components of X, and the component Y, to appear and/or disappear. There is no way to write the Assign operation to handle this sort of case. Forbidding such cases is not an option - it would cause generic contract model violations. Michael Borek "Death before Dishonour; Beer before Lunch" Michael Borek Software Services http://users.eastlink.ca/~borekking/professionalhome.html ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-15 22:09 ` Robert A Duff ` (2 preceding siblings ...) 2002-11-18 21:48 ` Eric @ 2002-11-19 14:38 ` Eric 3 siblings, 0 replies; 33+ messages in thread From: Eric @ 2002-11-19 14:38 UTC (permalink / raw) (Forgive me if this appears twice. My ISP went down just after my first submission and I haven't seen it posted after more than a day) "Robert A Duff" <bobduff@shell01.TheWorld.com> wrote in message news:wccbs4q8oys.fsf@shell01.TheWorld.com... [SNIP] > > By the way, have you read the AARM annotations that explain why we > didn't allow user-defined ":=" procedures? We certainly wanted to, > but we couldn't figure out how to make it work, so we invented Adjust, > which is not as powerful. I'd be interested in hearing better ideas > (even though it's probably too late). > > - Bob Hi, (I have reproduced the relevant annotation at the end.) The following come to mind (I haven't gone through all the possible ramifications and potential problems): 1. (The example in the AARM specifically refers to mutable, unconstrained record targets.) Consider an 'operator' "<-" (which is the current Ada implemented 'move of value') to disambiguate the procedure ":=". So the present non-limited controlled implementation of procedure ":=" looks like: procedure ":="(Target : in out TYPE; Source : in TYPE) is [anonymous_object : TYPE <- Source;] begin Finalize(Target); Target <- anonymous_object; [Finalize(anonymous_object);] Adjust(Target); end ":="; Since finalization should (must) always be done before the target is overwritten, Finalize and "<-" (plus any other constraint checks) can be combined into the attribute Uncontrolled_Assign so that the above looks like: procedure ":="(Target : in out TYPE; Source : in TYPE) is [anonymous_object : TYPE <- Source;] begin Target'Uncontrolled_Assign(anonymous_object); [Finalize(anonymous_object);] Adjust(Target); end ":="; Thus: a user defined implementation of ":=" could be: procedure ":="(Target : in out TYPE; Source : in TYPE) is New_Source : TYPE [<- ...]; -- Finalized on procedure return begin -- Fiddle with New_Source based on both Target and -- Source (and constraints) Target'Uncontrolled_Assign(New_Source); -- Fiddle with Target (probably unneeded) end ":="; Note that this use of Uncontrolled_Assign would probably require a recheck of any constraints. The only problem of significance that I see is the initiation of New_Source and how to prevent an infinite loop if it is initiated (using ":=") to Source. What is needed is programmer access to the "not really assignment" assign as is found in passing arguments to/from procedures. Perhaps: New_Source : TYPE'(<initial_value>) Also, as ":=" is defaulted to call Adjust, current code would not need be rewritten. 2. Change the assignment sequence from: anonymous_object <- Source; Finalize(Target); Target <- anonymous_object; Finalize(anonymous_object) Adjust(Target); To: anonymous_object <- Source; other_anonymous_object <- Target; Finalize(Target); Target <- anonymous_object; Finalize(anonymous_object); Adjust(Target, other_anonymous_object); Finalize(other_anonymous_object) with Adjust taking a second 'in' argument. This would allow Adjust to make use of the original value of Target. Not as useful as the above, but I have already met code where it would be useful. Here is the annotation (from Section 7.6 of the AARM): Reason: An alternative design for user-defined assignment might involve an Assign operation instead of Adjust: procedure Assign(Target : in out Controlled; Source : in out Controlled); Or perhaps even a syntax like this: procedure ":="(Target : in out Controlled; Source : in out Controlled); Assign (or ":=") would have the responsibility of doing the copy, as well as whatever else is necessary. This would have the advantage that the Assign operation knows about both the target and the source at the same time - it would be possible to do things like reuse storage belonging to the target, for example, which Adjust cannot do. However, this sort of design would not work in the case of unconstrained discriminated variables, because there is no way to change the discriminants individually. For example: type Mutable(D : Integer := 0) is record X : Array_Of_Controlled_Things(1..D); case D is when 17 => Y : Controlled_Thing; when others => null; end D; end record; An assignment to an unconstrained variable of type Mutable can cause some of the components of X, and the component Y, to appear and/or disappear. There is no way to write the Assign operation to handle this sort of case. Forbidding such cases is not an option - it would cause generic contract model violations. ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-14 19:25 ` Randy Brukardt 2002-11-15 10:04 ` Dmitry A. Kazakov @ 2002-11-15 21:41 ` Robert A Duff 2002-11-16 3:54 ` Randy Brukardt 1 sibling, 1 reply; 33+ messages in thread From: Robert A Duff @ 2002-11-15 21:41 UTC (permalink / raw) "Randy Brukardt" <randy@rrsoftware.com> writes: > Dmitry A. Kazakov wrote in message > >1. ":=" should dispatch in X:=Y to a disallowed operation, thus raise > >an exception and so refuse to copy the limited components. > > I don't know why this wasn't chosen. It seems better on the surface. > Possibly because of the desire to catch errors at compile-time rather > than run-time. Exactly. > However, that still doesn't solve the problem that we had in Claw. What > we wanted was a limited root window type with non-limited (thus > assignable) controls. That is, something like: > > Root_Window_Type (limited controlled) > Basic_Window_Type (limited) > Root_Dialog_Type (limited) > Modal_Dialog_Type (limited) > Root_Control_Type (non-limited) > Edit_Type (non-limited) > Checkbox_Type (non-limited) > Static_Text_Type (non-limited) > > [We want to be able to copy control objects because our goal was "no > visible pointers required" for the interface.] > > This does not have the classwide assignment problem, because only > Root_Control_Type has ":=", so it isn't possible to dispatch to a > limited type's ":=". > > We ended up making the whole hierarchy non-limited, but this means > implementing assignment for types for which is both a lot of work and > unneeded (such as application windows). Worse, we didn't meet our "no > pointers" goal, because we can't put limited objects into extentions of > application windows. (So you have to use pointers to do that.) > > I don't recall why you are not allowed to make the extension of the > limited type non-limited. (I didn't find anything in the AARM on this > subject.) I don't think it would work, because ":=" on a derived type copies the parent part, which is limited, and therefore not copyable: package Root_Windows is type Root_Window_Type is tagged limited private; private type Root_Window_Ptr is access all Root_Window_Type; type Root_Window_Type(Discrim: access Blah) is tagged limited record Self: Root_Window_Ptr := Root_Window_Type'Unchecked_Access; T: Some_Task_Type; end record; end Root_Windows; package Root_Controls is type Root_Control_Type is new Root_Window_Type with private is not limited; -- I'm inventing syntax here. ... end Root_Controls; X, Y: Root_Control_Type; ... X := Y; -- Bad. The assignment above is copying a task, which is bad news. It is also copying an access discriminant, which is bad news. Also, the component Self of X is supposed to point at X, and the assignment defeats that. I suppose it could work if all ancestor limited types are not private. Then we could add a rule saying that deriving a new non-limited type is OK if the ancestor types *could have been* non-limited -- that is, they don't violate any of the rules for non-limited types (e.g., no access discriminants allowed). But that would be a rather severe restriction -- I *want* most of my types to be private. Here's another alternative: you could invent a new kind of type -- "pseudo-limited". A pseudo-limited type disallows assignment statements, but *also* disallows all the things disallowed for non-limited types. A pseudo-limited type can have pseudo-limited components, and non-limited components, but not limited components. Then you could have a hierarchy with the root of the tree pseudo-limited, with some subbranches being limited and some non-limited (and some pseudo-limited). Sounds complicated. I haven't thought it through, so I'm not at all sure it even works. - Bob ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-15 21:41 ` Robert A Duff @ 2002-11-16 3:54 ` Randy Brukardt 0 siblings, 0 replies; 33+ messages in thread From: Randy Brukardt @ 2002-11-16 3:54 UTC (permalink / raw) Robert A Duff wrote in message ... >"Randy Brukardt" <randy@rrsoftware.com> writes: >> I don't recall why you are not allowed to make the extension of the >> limited type non-limited. (I didn't find anything in the AARM on this >> subject.) > >I don't think it would work, because ":=" on a derived type copies the >parent part, which is limited, and therefore not copyable: >... >The assignment above is copying a task, which is bad news. It is also >copying an access discriminant, which is bad news. Also, the component >Self of X is supposed to point at X, and the assignment defeats that. I knew there was a reason, I just couldn't figure out what it was. I'm surprised that this discussion is not in the AARM, because it is such a restrictive rule that you'd think that there would have been a justification for it somewhere. >I suppose it could work if all ancestor limited types are not private. >Then we could add a rule saying that deriving a new non-limited type is >OK if the ancestor types *could have been* non-limited -- that is, they >don't violate any of the rules for non-limited types (e.g., no access >discriminants allowed). > >But that would be a rather severe restriction -- I *want* most of my >types to be private. No, that's not going to work. And, of course, breaking privateness would also be a bad idea (even though it would work in this case. >Here's another alternative: you could invent a new kind of type -- >"pseudo-limited". A pseudo-limited type disallows assignment >statements, but *also* disallows all the things disallowed for >non-limited types. A pseudo-limited type can have pseudo-limited >components, and non-limited components, but not limited components. >Then you could have a hierarchy with the root of the tree >pseudo-limited, with some subbranches being limited and some non-limited >(and some pseudo-limited). That would work, I think. >Sounds complicated. I haven't thought it through, so I'm not at all >sure it even works. But I have to agree with the 'sounds complicated'. I doubt that this problem is severe enough to justify a solution like this. (We've had other problems with simpler solutions shot down, after all.) Randy. ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-14 14:27 ` Dmitry A. Kazakov 2002-11-14 19:25 ` Randy Brukardt @ 2002-11-15 0:30 ` Robert A Duff 2002-11-15 10:22 ` Dmitry A. Kazakov 1 sibling, 1 reply; 33+ messages in thread From: Robert A Duff @ 2002-11-15 0:30 UTC (permalink / raw) Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes: > Which also raises an interesting question, whether T'Class should > always inherit "non-limitness" of T. Or more generally shouldn't one > have an ability to disallow primitive operations (like ":=" in case of > non-limited->limited mutation)? > > Let we allow disallowing, then either > > 1. ":=" should dispatch in X:=Y to a disallowed operation, thus raise > an exception and so refuse to copy the limited components. Compile time errors are good. Exceptions (run-time errors) are evil. This is not SmallTalk, where you can dispatch to a method that does not exist. - Bob ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-15 0:30 ` Robert A Duff @ 2002-11-15 10:22 ` Dmitry A. Kazakov 2002-11-15 21:56 ` Robert A Duff 0 siblings, 1 reply; 33+ messages in thread From: Dmitry A. Kazakov @ 2002-11-15 10:22 UTC (permalink / raw) On Fri, 15 Nov 2002 00:30:03 GMT, Robert A Duff <bobduff@shell01.TheWorld.com> wrote: >Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes: > >> Which also raises an interesting question, whether T'Class should >> always inherit "non-limitness" of T. Or more generally shouldn't one >> have an ability to disallow primitive operations (like ":=" in case of >> non-limited->limited mutation)? >> >> Let we allow disallowing, then either >> >> 1. ":=" should dispatch in X:=Y to a disallowed operation, thus raise >> an exception and so refuse to copy the limited components. > >Compile time errors are good. Exceptions (run-time errors) are evil. Absolutely >This is not SmallTalk, where you can dispatch to a method that does not >exist. Sure? And what about this: type A is tagged ... procedure Foo (L, R : A); type B is new A with .... X : A'Class := Some_A; Y : A'Class := Some_B; Foo (X, Y); -- Oops, dispatching to nowhere! [ Not that I argue for SmallTalk, of course (:-)) ] Then disallowing is already allowed for non-tagged types = "is abstract". Further one can always override with a subroutine that throws Program_Error. Is that better? IMO it is the same. The only real difference is that one cannot get rid of overloading of the undesired operation. What is actually required. I think that there could be situations where it would be useful to disallow an operation in the public interface and to override it with something working in the private one. --- Regards, Dmitry Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-15 10:22 ` Dmitry A. Kazakov @ 2002-11-15 21:56 ` Robert A Duff 2002-11-16 12:39 ` Dmitry A. Kazakov 0 siblings, 1 reply; 33+ messages in thread From: Robert A Duff @ 2002-11-15 21:56 UTC (permalink / raw) Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes: > On Fri, 15 Nov 2002 00:30:03 GMT, Robert A Duff > <bobduff@shell01.TheWorld.com> wrote: > > >Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes: > Sure? And what about this: > > type A is tagged ... > procedure Foo (L, R : A); > > type B is new A with .... > > X : A'Class := Some_A; > Y : A'Class := Some_B; > > Foo (X, Y); -- Oops, dispatching to nowhere! True. But I'm not happy about it. And it doesn't mean single-argument dispatching should be made more dangerous to match double-arg dispatching. ;-) > [ Not that I argue for SmallTalk, of course (:-)) ] ;-) > Then disallowing is already allowed for non-tagged types = > "is abstract". > > Further one can always override with a subroutine that throws > Program_Error. Is that better? IMO it is the same. Yes, it is the same. I see no reason to add special syntax to make it easy, though. Note that Java more-or-less prevents this problem by making exceptions part of the visible contract. I think they got some of the details wrong, but they are on the right track. The Java rules are a pain, but I think they could be modified to make them work nicely. >... The only real > difference is that one cannot get rid of overloading of the undesired > operation. What is actually required. I think that there could be > situations where it would be useful to disallow an operation in the > public interface and to override it with something working in the > private one. Hmm. What example? It seems to me that hiding/disallowing the operation for the derived type is dishonest, because a client can always call that operation by converting to the parent type 'Class and dispatching. Note that you can say: type T is new A with private; ... type T is new B with record... where B is derived from A, and has more operations. This is a useful capability, and is similar to what you asked for above. The "more operations" are visible only inside T package. Clients can't convert to B, because they can't see that T is "really" derived from B. Here's an idea I've been thinking about for some years, which might address your desire to "take away" operations: Define two kinds of inheritance, "is a" inheritance, and "is like a" inheritance. When you use "is a" inheritance, you can only *add* operations, and you can convert to the parent type. When you use "is like a" inheritance, you can also take away operations, but you are forbidden from converting to the parent type. With "is like a" inheritance, you are defining a new abstraction that is similar to the parent, but you don't claim that it "is a" parent, and you don't want to view the new type *as* a parent. What do you think? - Bob ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-15 21:56 ` Robert A Duff @ 2002-11-16 12:39 ` Dmitry A. Kazakov 0 siblings, 0 replies; 33+ messages in thread From: Dmitry A. Kazakov @ 2002-11-16 12:39 UTC (permalink / raw) Robert A Duff wrote: > Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes: > >> On Fri, 15 Nov 2002 00:30:03 GMT, Robert A Duff >> <bobduff@shell01.TheWorld.com> wrote: >> >> >Dmitry A. Kazakov <mailbox@dmitry-kazakov.de> writes: > >> Sure? And what about this: >> >> type A is tagged ... >> procedure Foo (L, R : A); >> >> type B is new A with .... >> >> X : A'Class := Some_A; >> Y : A'Class := Some_B; >> >> Foo (X, Y); -- Oops, dispatching to nowhere! > > True. But I'm not happy about it. And it doesn't mean single-argument > dispatching should be made more dangerous to match double-arg > dispatching. ;-) Of course not. However there is a difference. My example can be cured by introducing multiple dispatch. The case when Circle is derived from Ellipse and Resize (E : in out Ellipse; X_Size, Y_Size : Distance) has to be disallowed cannot be cured at all. >> Further one can always override with a subroutine that throws >> Program_Error. Is that better? IMO it is the same. > > Yes, it is the same. I see no reason to add special syntax to make it > easy, though. 1. Earlier error detection. If you disallow an operation, then in a statical case, you will get a compile-time error 2. Getting rid of overloading contaminations > Note that Java more-or-less prevents this problem by making exceptions > part of the visible contract. I think they got some of the details > wrong, but they are on the right track. The Java rules are a pain, > but I think they could be modified to make them work nicely. I agree. While developing large programs, tracking down the exceptions becomes a real pain. I have no idea how to do it properly, but surely the exceptions should be a part of the contract and another important thing, there should be a way to somehow tell to "exception when =>", what is the full list of the alternatives, so that it could work as safe as "case ... when =>" does. >>... The only real >> difference is that one cannot get rid of overloading of the undesired >> operation. What is actually required. I think that there could be >> situations where it would be useful to disallow an operation in the >> public interface and to override it with something working in the >> private one. > > Hmm. What example? It seems to me that hiding/disallowing the > operation for the derived type is dishonest, because a client can always > call that operation by converting to the parent type 'Class and > dispatching. Ah, that is re-dispatch, it is a vicious thing. I wished it to be removed from Ada. Converting to Parent'Class should be more than just view change, at least in case of disallowing => breaking Parent's contract. It means that the result of Parent'Class (A_Child) should a NEW object which is really of Parent type and, lo, you can safely dispatch to any operation of Parent! > Note that you can say: > > type T is new A with private; > ... > type T is new B with record... > > where B is derived from A, and has more operations. > This is a useful capability, and is similar to what you asked for above. > The "more operations" are visible only inside T package. > Clients can't convert to B, because they can't see that T is "really" > derived from B. > > Here's an idea I've been thinking about for some years, which might > address your desire to "take away" operations: > Define two kinds of inheritance, "is a" inheritance, and "is like a" > inheritance. When you use "is a" inheritance, you can only *add* > operations, and you can convert to the parent type. When you use "is > like a" inheritance, you can also take away operations, but you are > forbidden from converting to the parent type. With "is like a" > inheritance, you are defining a new abstraction that is similar to > the parent, but you don't claim that it "is a" parent, and you don't > want to view the new type *as* a parent. What do you think? It looks very close to my understanding of the problem. Your "is a" inheritance is one when we inherit both the contract and the implementation of the parent type, i.e. we extend it. This is a sort of LSP-subtyping, however, not enforced. "is like a" inheritance is when we inherit only the contract (at least in the public part, in the private part it could be still "is a"). For instance, let I have the type String, if I derive from it by "is like a", then I am absolutely free to implement it as a record. Then you say that conversion to parent should be forbidden. Why? Because the compiler has no clue how to do it? So let's make it a part of the contract. I.e. if I derive My_String from String, I should also provide My_String->String conversion, if I wish to access in-methods of String. I should define My_String<-String if I wish to access out-methods of String. I should define both if I wish to access everything. -- Regards, Dmitry A. Kazakov www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-14 9:26 ` Mike 2002-11-14 11:43 ` David C. Hoos, Sr. 2002-11-14 12:33 ` Jean-Pierre Rosen @ 2002-11-14 23:39 ` Robert A Duff 2002-11-15 21:51 ` Mike 2 siblings, 1 reply; 33+ messages in thread From: Robert A Duff @ 2002-11-14 23:39 UTC (permalink / raw) michael.jackson5@virgin.net (Mike) writes: > How can assignment by upcasting the extended type possibly affect the > limited component? If you have "type T2 is new T1 with...", then it is important that if T2 is limited, then T1'Class must also be limited, because ":=" on T1'Class objects will copy the T2 part, if the objects' tag happens to be T2'Tag. In Ada, T1'Class is limited if and only if T1 is limited. So that means the whole hierarchy of tagged types has to be either limited or nonlimited. I'm not sure if it would cause semantic troubles to allow a nonlimited T1 with a limited T1'Class (assuming one could invent some syntax for saying so). Interesting question. - Bob ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-14 23:39 ` Robert A Duff @ 2002-11-15 21:51 ` Mike 0 siblings, 0 replies; 33+ messages in thread From: Mike @ 2002-11-15 21:51 UTC (permalink / raw) I originally wrote: > > How can assignment by upcasting the extended type possibly affect the > > limited component? > Bob replied: > If you have "type T2 is new T1 with...", then it is important that if T2 > is limited, then T1'Class must also be limited, because ":=" on T1'Class > objects will copy the T2 part, if the objects' tag happens to be T2'Tag. > > In Ada, T1'Class is limited if and only if T1 is limited. > So that means the whole hierarchy of tagged types has to be > either limited or nonlimited. I'm not sure if it would cause semantic > troubles to allow a nonlimited T1 with a limited T1'Class (assuming one > could invent some syntax for saying so). Interesting question. Aha. That is the reason! Thanks Bob, Mike ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-13 10:03 Mike 2002-11-13 12:06 ` Jean-Pierre Rosen @ 2002-11-13 14:28 ` Robert A Duff 2002-11-14 9:33 ` Mike 1 sibling, 1 reply; 33+ messages in thread From: Robert A Duff @ 2002-11-13 14:28 UTC (permalink / raw) michael.jackson5@virgin.net (Mike) writes: > How do I extend a non-limited tagged type to add a limited component? You don't. ;-) You can extend it with a pointer-to-limited component, however. But your best bet may be to make the non-limited type limited. Or make the component non-limited. - Bob ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-13 14:28 ` Robert A Duff @ 2002-11-14 9:33 ` Mike 2002-11-14 9:35 ` Lutz Donnerhacke 2002-11-14 21:41 ` Robert A Duff 0 siblings, 2 replies; 33+ messages in thread From: Mike @ 2002-11-14 9:33 UTC (permalink / raw) I wrote > > How do I extend a non-limited tagged type to add a limited component? Robert A Duff replied > You don't. ;-) You can extend it with a pointer-to-limited component, > however. But your best bet may be to make the non-limited type > limited. Or make the component non-limited. Unfortunately neither the base type nor the limited component are under my control. I have thought about the pointer-to-limited option but find that there is no pointer type declared in the package that declares the limited type and consequently there are no operations on the limited type that take a pointer type. Am I allowed to create my own pointer-to-limited type and de-reference it for use later? Wouldn't the act of de-referenceing be an implicit assignment? Regards, Mike. ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-14 9:33 ` Mike @ 2002-11-14 9:35 ` Lutz Donnerhacke 2002-11-14 21:41 ` Robert A Duff 1 sibling, 0 replies; 33+ messages in thread From: Lutz Donnerhacke @ 2002-11-14 9:35 UTC (permalink / raw) * Mike wrote: > Am I allowed to create my own pointer-to-limited type and de-reference > it for use later? Yes. This enshures the locality of the pointer use. That's why it's Ada style to not provide pointers in the base packets. > Wouldn't the act of de-referenceing be an implicit assignment? No. ^ permalink raw reply [flat|nested] 33+ messages in thread
* Re: Extension of non-limited type needs limited component 2002-11-14 9:33 ` Mike 2002-11-14 9:35 ` Lutz Donnerhacke @ 2002-11-14 21:41 ` Robert A Duff 1 sibling, 0 replies; 33+ messages in thread From: Robert A Duff @ 2002-11-14 21:41 UTC (permalink / raw) michael.jackson5@virgin.net (Mike) writes: > Am I allowed to create my own pointer-to-limited type and de-reference > it for use later? Yes. You just need to say ".all" whenever you want to call the preexisting procedures. The only problem with using a pointer that then you have to worry about storage management. You'll probably end up allocating the thing in the heap (with "new"), and then you have to worry about deallocating it. >... Wouldn't the act of de-referenceing be an implicit > assignment? No. "X.all" returns the heap object that the pointer points at. It does not fetch the value out of that object. The fetch operation is really what limited types want to disallow. When you say P(X.all), the heap object will be passed by reference if it is really limited -- no copy is made. - Bob ^ permalink raw reply [flat|nested] 33+ messages in thread
end of thread, other threads:[~2002-11-19 14:38 UTC | newest] Thread overview: 33+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2002-11-15 10:47 Extension of non-limited type needs limited component Grein, Christoph 2002-11-15 12:12 ` Dmitry A. Kazakov 2002-11-15 13:29 ` Jean-Pierre Rosen 2002-11-15 14:34 ` Dmitry A. Kazakov 2002-11-15 21:26 ` Robert A Duff -- strict thread matches above, loose matches on Subject: below -- 2002-11-13 10:03 Mike 2002-11-13 12:06 ` Jean-Pierre Rosen 2002-11-14 9:26 ` Mike 2002-11-14 11:43 ` David C. Hoos, Sr. 2002-11-14 12:33 ` Jean-Pierre Rosen 2002-11-14 14:27 ` Dmitry A. Kazakov 2002-11-14 19:25 ` Randy Brukardt 2002-11-15 10:04 ` Dmitry A. Kazakov 2002-11-15 22:09 ` Robert A Duff 2002-11-16 12:39 ` Dmitry A. Kazakov 2002-11-16 16:15 ` Robert A Duff 2002-11-17 11:14 ` Dmitry A. Kazakov 2002-11-17 12:26 ` Dale Stanbrough 2002-11-18 20:33 ` Randy Brukardt 2002-11-18 21:48 ` Eric 2002-11-19 14:38 ` Eric 2002-11-15 21:41 ` Robert A Duff 2002-11-16 3:54 ` Randy Brukardt 2002-11-15 0:30 ` Robert A Duff 2002-11-15 10:22 ` Dmitry A. Kazakov 2002-11-15 21:56 ` Robert A Duff 2002-11-16 12:39 ` Dmitry A. Kazakov 2002-11-14 23:39 ` Robert A Duff 2002-11-15 21:51 ` Mike 2002-11-13 14:28 ` Robert A Duff 2002-11-14 9:33 ` Mike 2002-11-14 9:35 ` Lutz Donnerhacke 2002-11-14 21:41 ` Robert A Duff
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox