* Is this expected behavior or not @ 2013-03-11 19:42 Anh Vo 2013-03-11 20:01 ` Robert A Duff 0 siblings, 1 reply; 242+ messages in thread From: Anh Vo @ 2013-03-11 19:42 UTC (permalink / raw) I have read ARM section 3.2.4, Subtype Predicates, I did not see any rules prohibiting from using attribute 'Succ as contained in the code nipet below. I would expect Prime'Succ (3) return 5 for next prime number. However, 4 is returned instead. Is this a correct behavior? pragma Assertion_Policy (Check); with Ada.Text_Io; with Ada.Exceptions; use Ada; procedure Predicates_Test is use Text_Io; subtype Prime is Natural range 1 .. 1000 with Dynamic_Predicate => (case Prime is when 1 => False, when 2 => True, when others => Prime mod 2 /= 0 and then (for all K in 3 .. Prime - 1 => Prime mod K /= 0)); Current_Prime_Number : constant Natural := 3; Next_Prime_Number : constant Natural := 5; begin Put_Line ("Predicates_Test starts"); if Prime'Succ (Current_Prime_Number) = Next_Prime_Number then Put_Line ("The next prime number matches expectation"); else Put_Line (Prime'Succ(Current_Prime_Number)'Img & " is not an expected number"); end if; Put_Line ("Predicates_Test ends"); exception when Err : others => Put_Line ("Houston we have a problem: " & Exceptions.Exception_Information(Err)); end Predicates_Test; ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-11 19:42 Is this expected behavior or not Anh Vo @ 2013-03-11 20:01 ` Robert A Duff 2013-03-11 20:41 ` Shark8 ` (2 more replies) 0 siblings, 3 replies; 242+ messages in thread From: Robert A Duff @ 2013-03-11 20:01 UTC (permalink / raw) Anh Vo <anhvofrcaus@gmail.com> writes: > I have read ARM section 3.2.4, Subtype Predicates, I did not see any > rules prohibiting from using attribute 'Succ as contained in the code > nipet below. I would expect Prime'Succ (3) return 5 for next prime > number. However, 4 is returned instead. Is this a correct behavior? It is standard-conforming behavior. Prime'Succ is the same as Prime'Base'Succ. Many other attributes behave the same way. This has been true since Ada 83. For example, Prime'Succ(1000) = 1001, and does not raise an exception. Positive'Image (-10) = "-10". > subtype Prime is Natural range 1 .. 1000 - Bob ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-11 20:01 ` Robert A Duff @ 2013-03-11 20:41 ` Shark8 2013-03-12 9:27 ` Dmitry A. Kazakov 2013-03-11 20:43 ` Anh Vo 2013-03-12 9:17 ` Dmitry A. Kazakov 2 siblings, 1 reply; 242+ messages in thread From: Shark8 @ 2013-03-11 20:41 UTC (permalink / raw) On Monday, March 11, 2013 2:01:04 PM UTC-6, Robert A Duff wrote: > Anh Vo <anhvofrcaus@gmail.com> writes: > > > I have read ARM section 3.2.4, Subtype Predicates, I did not see any > > rules prohibiting from using attribute 'Succ as contained in the code > > nipet below. I would expect Prime'Succ (3) return 5 for next prime > > number. However, 4 is returned instead. Is this a correct behavior? > > It is standard-conforming behavior. Prime'Succ is the same as > Prime'Base'Succ. Many other attributes behave the same way. > This has been true since Ada 83. For example, Prime'Succ(1000) = 1001, > and does not raise an exception. This is something that is especially useful: consider the instance where you are slicing out portions of an array, say parsing out a STRING:VALUE sort of construction or doing some [certain] linear combinations: Key : Constant String := Get_Part( Element, Before ); Val : Constant String := Get_Part( Element, After ); -- Where Get_Part is: Type Portion is ( Before, After ); Function Get_Part( Item : String; Part : Portion ) Return String is Use Ada.Strings.Fixed; Pos : Constant Natural := Index( Source => Item, Pattern => "" & Seperator ); SubType Head is Positive Range Item'First..Integer'Pred(Pos); SubType Tail is Positive Range Positive'Succ(Pos)..Item'Last; Begin Return (if Part = Before then Item(Head) else Item(Tail)); End Get_Part; We don't want the subtype "Head" to fail when the Pred'(Pos) is applied [and Pos = 1] while declaring the range; this precisely because the null-range is valid and what we desire. The construction of range 1..0 should therefore not generate an exception despite 0 not being a member of Positive. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-11 20:41 ` Shark8 @ 2013-03-12 9:27 ` Dmitry A. Kazakov 2013-03-12 17:19 ` Robert A Duff 2013-03-12 23:14 ` Randy Brukardt 0 siblings, 2 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-12 9:27 UTC (permalink / raw) On Mon, 11 Mar 2013 13:41:43 -0700 (PDT), Shark8 wrote: [...] > We don't want the subtype "Head" to fail when the Pred'(Pos) is applied > [and Pos = 1] while declaring the range; this precisely because the > null-range is valid and what we desire. The construction of range 1..0 > should therefore not generate an exception despite 0 not being a member of > Positive. The issue of the bounds of an empty string is not related to subtypes. It has a long history. But in short, you should not break one thing in order to save another. The semantics of 'Pred and 'Succ shall be properly defined in terms of convariance of the argument and the result. There are arguments for and against contravariant results. It goes straight to the circle-ellipse controversy. As Robert pointed out Ada tends to contravariance for numeric operations. But it is not a trivial choice for 'Pred, 'Succ, 'Range. Consider for I in Prime'Range loop -- What is this supposed to mean? ... -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-12 9:27 ` Dmitry A. Kazakov @ 2013-03-12 17:19 ` Robert A Duff 2013-03-12 17:42 ` Dmitry A. Kazakov 2013-03-12 23:14 ` Randy Brukardt 1 sibling, 1 reply; 242+ messages in thread From: Robert A Duff @ 2013-03-12 17:19 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > The semantics of 'Pred and 'Succ shall be properly defined in terms of > convariance of the argument and the result. There are arguments for and > against contravariant results. It goes straight to the circle-ellipse > controversy. The profile of 'Succ is given in RM-3.5(23): function S'Succ (Arg: S'Base) return S'Base; It's neither contravariant nor covariant -- it's invariant. One way to think of it is that S'Succ is just a shorthand for S'Base'Succ. I admit that's somewhat confusing, but it's just like operator "+" -- there's no "+" specific to Positive, nor is there 'Succ specific to Positive -- both operate on Integer'Base, and don't do any range checking on their parameters or result. > As Robert pointed out Ada tends to contravariance for numeric operations. > But it is not a trivial choice for 'Pred, 'Succ, 'Range. Consider > > for I in Prime'Range loop -- What is this supposed to mean? > ... It doesn't mean anything -- it's illegal. - Bob ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-12 17:19 ` Robert A Duff @ 2013-03-12 17:42 ` Dmitry A. Kazakov 2013-03-12 18:04 ` Georg Bauhaus 2013-03-12 23:21 ` Randy Brukardt 0 siblings, 2 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-12 17:42 UTC (permalink / raw) On Tue, 12 Mar 2013 13:19:06 -0400, Robert A Duff wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > >> The semantics of 'Pred and 'Succ shall be properly defined in terms of >> convariance of the argument and the result. There are arguments for and >> against contravariant results. It goes straight to the circle-ellipse >> controversy. > > The profile of 'Succ is given in RM-3.5(23): > > function S'Succ (Arg: S'Base) return S'Base; > > It's neither contravariant nor covariant -- it's invariant. Invariant = contravariant. >> for I in Prime'Range loop -- What is this supposed to mean? >> ... > > It doesn't mean anything -- it's illegal. Why Prime'Succ is legal then? And what about: for I in Prime'First..Prime'Last loop -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-12 17:42 ` Dmitry A. Kazakov @ 2013-03-12 18:04 ` Georg Bauhaus 2013-03-12 18:21 ` Dmitry A. Kazakov 2013-03-12 23:21 ` Randy Brukardt 1 sibling, 1 reply; 242+ messages in thread From: Georg Bauhaus @ 2013-03-12 18:04 UTC (permalink / raw) On 12.03.13 18:42, Dmitry A. Kazakov wrote: > On Tue, 12 Mar 2013 13:19:06 -0400, Robert A Duff wrote: > >> > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: >> > >>> >> The semantics of 'Pred and 'Succ shall be properly defined in terms of >>> >> convariance of the argument and the result. There are arguments for and >>> >> against contravariant results. It goes straight to the circle-ellipse >>> >> controversy. >> > >> > The profile of 'Succ is given in RM-3.5(23): >> > >> > function S'Succ (Arg: S'Base) return S'Base; >> > >> > It's neither contravariant nor covariant -- it's invariant. > Invariant = contravariant. In Ada? For non-tagged types? ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-12 18:04 ` Georg Bauhaus @ 2013-03-12 18:21 ` Dmitry A. Kazakov 2013-03-12 22:23 ` Georg Bauhaus 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-12 18:21 UTC (permalink / raw) On Tue, 12 Mar 2013 19:04:31 +0100, Georg Bauhaus wrote: > On 12.03.13 18:42, Dmitry A. Kazakov wrote: >> On Tue, 12 Mar 2013 13:19:06 -0400, Robert A Duff wrote: >> >>> > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: >>> > >>>> >> The semantics of 'Pred and 'Succ shall be properly defined in terms of >>>> >> convariance of the argument and the result. There are arguments for and >>>> >> against contravariant results. It goes straight to the circle-ellipse >>>> >> controversy. >>> > >>> > The profile of 'Succ is given in RM-3.5(23): >>> > >>> > function S'Succ (Arg: S'Base) return S'Base; >>> > >>> > It's neither contravariant nor covariant -- it's invariant. >> Invariant = contravariant. > > In Ada? For non-tagged types? Tagged is a special case, nothing more. When the compiler allows instances of Prime in an operation of Prime'Base that means that Prime inherits the operation <=> Prime is a subtype of Prime'Base [in an interface having the operation]. In our case the operation is 'Succ. Now if the argument, or result of 'Succ stays Prime'Base that is the definition of the operation being contravariant in it. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-12 18:21 ` Dmitry A. Kazakov @ 2013-03-12 22:23 ` Georg Bauhaus 2013-03-13 8:49 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Georg Bauhaus @ 2013-03-12 22:23 UTC (permalink / raw) On 12.03.13 19:21, Dmitry A. Kazakov wrote: > On Tue, 12 Mar 2013 19:04:31 +0100, Georg Bauhaus wrote: > >> On 12.03.13 18:42, Dmitry A. Kazakov wrote: >>> On Tue, 12 Mar 2013 13:19:06 -0400, Robert A Duff wrote: >>>>> The profile of 'Succ is given in RM-3.5(23): >>>>> >>>>> function S'Succ (Arg: S'Base) return S'Base; >>>>> >>>>> It's neither contravariant nor covariant -- it's invariant. >>> Invariant = contravariant. >> >> In Ada? For non-tagged types? > > Tagged is a special case, nothing more. > > When the compiler allows instances of Prime in an operation of Prime'Base > that means that Prime inherits the operation No inheritance involved here, in Ada, where the object involved simply is of an unconstrained subtype of the given type of Prime, which is not Prime. This type, not Prime (which isn't a type), has the attribute 'Succ, irrespective of the subtype, and irrespective of some differently formalizing theory of types that, I think, can only help to set things straight here if every word used in every non-Ada argument gets a subscript indicating its frame of reference. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-12 22:23 ` Georg Bauhaus @ 2013-03-13 8:49 ` Dmitry A. Kazakov 2013-03-13 9:45 ` J-P. Rosen 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-13 8:49 UTC (permalink / raw) On Tue, 12 Mar 2013 23:23:52 +0100, Georg Bauhaus wrote: > On 12.03.13 19:21, Dmitry A. Kazakov wrote: >> On Tue, 12 Mar 2013 19:04:31 +0100, Georg Bauhaus wrote: >> >>> On 12.03.13 18:42, Dmitry A. Kazakov wrote: >>>> On Tue, 12 Mar 2013 13:19:06 -0400, Robert A Duff wrote: > >>>>>> The profile of 'Succ is given in RM-3.5(23): >>>>>> >>>>>> function S'Succ (Arg: S'Base) return S'Base; >>>>>> >>>>>> It's neither contravariant nor covariant -- it's invariant. >>>> Invariant = contravariant. >>> >>> In Ada? For non-tagged types? >> >> Tagged is a special case, nothing more. >> >> When the compiler allows instances of Prime in an operation of Prime'Base >> that means that Prime inherits the operation > > No inheritance involved here, in Ada, where the object involved simply is of > an unconstrained subtype of the given type of Prime, which is not Prime. You have two types T and S and one operation F. Provided Ada is a typed language. F (X : T) shall not accept S, unless inherited. In Ada subtype (here subtype is Ada-subtype) operations are inherited per composition with conversion to the base type which is null for in-arguments and sometimes range-check of outs (not always, though). E.g. F (X : S) = F (S'Base (X)) S is a subtype *because* it inherits F. All three statements are equivalent: 1. S is a subtype of T 2. S inherits operations of T 3. S is substitutable in operations of T (syntactically, not LSP) When you inherit with null-conversion, as it is the case with 'Succ you break the semantics of the result, which is not new. It is well-known LSP issue that contravariance of out-arguments/results is broken upon specialization. Which is trivial to see. Prime is not a subtype which can preserve Integer's 'Succ. Nothing can be done about it. Neither can Prime preserve +,-,*,/. Prime is basically not Integer. Not every set of integers is Integer, and subsetting /= subtyping. > This type, not Prime (which isn't a type), How so? Subtype certainly is a type. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 8:49 ` Dmitry A. Kazakov @ 2013-03-13 9:45 ` J-P. Rosen 2013-03-13 13:31 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: J-P. Rosen @ 2013-03-13 9:45 UTC (permalink / raw) Le 13/03/2013 09:49, Dmitry A. Kazakov a �crit : > In Ada subtype > (here subtype is Ada-subtype) operations are inherited per composition with > conversion to the base type which is null for in-arguments and sometimes > range-check of outs (not always, though). E.g. > > F (X : S) = F (S'Base (X)) > > S is a subtype *because* it inherits F. Not at all. In Ada, a type is a set of values. A subtype is the SAME TYPE, restricted to a subset of the values (the "constraint"). This feature does not exist in other OO languages, however it is not a reason to try to force this notion on how a more or less similar effect could be achieved in other languages. A subtype has the same operation as its base type, not copies of the operations as with inheritance. -- J-P. Rosen Adalog 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00 http://www.adalog.fr ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 9:45 ` J-P. Rosen @ 2013-03-13 13:31 ` Dmitry A. Kazakov 2013-03-13 14:34 ` Georg Bauhaus 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-13 13:31 UTC (permalink / raw) On Wed, 13 Mar 2013 10:45:54 +0100, J-P. Rosen wrote: > Le 13/03/2013 09:49, Dmitry A. Kazakov a �crit : >> In Ada subtype >> (here subtype is Ada-subtype) operations are inherited per composition with >> conversion to the base type which is null for in-arguments and sometimes >> range-check of outs (not always, though). E.g. >> >> F (X : S) = F (S'Base (X)) >> >> S is a subtype *because* it inherits F. > > Not at all. In Ada, a type is a set of values. A type is a set of values bound by operations defined on them. It is values+operations. Even under your (wrong) definition Positive is still different from Integer because Positive does not have values like -1. > A subtype is the SAME > TYPE, restricted to a subset of the values (the "constraint"). There is a simple empiric test to determine if two types are same. They are if there is no language means to distinguish them either at compile or at run-time. Ada subtypes are proper types and they are distinguishable from each other and their bases. E.g. these two programs are not equivalent: X : Integer := -1; and X : Positive := -1; You cannot replace Integer with Positive without changing the semantics of any possible program, hence they are different. Note that since the above is the weakest possible definition of dissimilarity. Any other would be only stronger. Therefore, there is no way to have Ada's Positive and Integer "same." > A subtype has the same operation > as its base type, not copies of the operations as with inheritance. In a typed language any type has only operations of its own. All other operations give type error. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 13:31 ` Dmitry A. Kazakov @ 2013-03-13 14:34 ` Georg Bauhaus 2013-03-13 15:51 ` Dmitry A. Kazakov 2013-03-13 17:05 ` Shark8 0 siblings, 2 replies; 242+ messages in thread From: Georg Bauhaus @ 2013-03-13 14:34 UTC (permalink / raw) On 13.03.13 14:31, Dmitry A. Kazakov wrote: > On Wed, 13 Mar 2013 10:45:54 +0100, J-P. Rosen wrote: > >> Le 13/03/2013 09:49, Dmitry A. Kazakov a �crit : >>> In Ada subtype >>> (here subtype is Ada-subtype) operations are inherited per composition with >>> conversion to the base type which is null for in-arguments and sometimes >>> range-check of outs (not always, though). E.g. >>> >>> F (X : S) = F (S'Base (X)) >>> >>> S is a subtype *because* it inherits F. >> >> Not at all. In Ada, a type is a set of values. > > A type is a set of values bound by operations defined on them. It is > values+operations. The LRM does not define what it means for sets of values being "bound by operations". It does define subtypes and types. > Even under your (wrong) definition Positive is still different from Integer > because Positive does not have values like -1. I don't think this is true. In Ada, Positive and Integer are not different types. The names Positive and Integer refer to the same type; objects happen to be associated with different range constraints. See Ivan Godard's comment on his invention, the subtype in Ada: http://newsgroups.derkeiler.com/Archive/Comp/comp.arch/2012-08/msg00360.html > Ada subtypes are proper types External observations inspired by whichever type theory do not apply when judging things from the Ada perspective. I'd find observations interesting only when someone is pondering language design, not when explaining properties of an existing language. Randy mentioned a time machine... > E.g. these two programs are not equivalent: > > X : Integer := -1; ... > You cannot replace Integer with Positive without changing the semantics of > any possible program, hence they are different. The difference only means that different range constraints yield different programs. Nothing about different Ada types here. X : Integer := -2; yields another semantically different program. Does the difference (assigning -2, not -1) tell anything about the Ada type of X? Constraint_Error on assigning a negative value to a variable whose range constraint requires positive values is a consequence of range checking *in* the same type's set. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 14:34 ` Georg Bauhaus @ 2013-03-13 15:51 ` Dmitry A. Kazakov 2013-03-13 16:56 ` Jeffrey Carter 2013-03-13 17:32 ` Georg Bauhaus 2013-03-13 17:05 ` Shark8 1 sibling, 2 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-13 15:51 UTC (permalink / raw) On Wed, 13 Mar 2013 15:34:41 +0100, Georg Bauhaus wrote: > On 13.03.13 14:31, Dmitry A. Kazakov wrote: >> On Wed, 13 Mar 2013 10:45:54 +0100, J-P. Rosen wrote: >> >>> Le 13/03/2013 09:49, Dmitry A. Kazakov a �crit : >>>> In Ada subtype >>>> (here subtype is Ada-subtype) operations are inherited per composition with >>>> conversion to the base type which is null for in-arguments and sometimes >>>> range-check of outs (not always, though). E.g. >>>> >>>> F (X : S) = F (S'Base (X)) >>>> >>>> S is a subtype *because* it inherits F. >>> >>> Not at all. In Ada, a type is a set of values. >> >> A type is a set of values bound by operations defined on them. It is >> values+operations. > > The LRM does not define what it means for sets of values being > "bound by operations". It does define subtypes and types. LRM is irrelevant here. See http://en.wikipedia.org/wiki/Abstract_data_type >> Even under your (wrong) definition Positive is still different from Integer >> because Positive does not have values like -1. > > I don't think this is true. Well, well, according to you Ada's Positive has -1 as a value? >> Ada subtypes are proper types > > External observations inspired by whichever type theory do > not apply when judging things from the Ada perspective. How a type theory may not apply to a programming language? Anyway if you don't like the theory X, you should propose another theory. But whichever theory you take, it cannot be consistent with Integer and Positive being same type, while considering Ada typed. Ada is typed. Integer and Positive are not same. >> E.g. these two programs are not equivalent: >> >> X : Integer := -1; > ... >> You cannot replace Integer with Positive without changing the semantics of >> any possible program, hence they are different. > > The difference only means that different range constraints yield > different programs. The difference exists. q.e.d. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 15:51 ` Dmitry A. Kazakov @ 2013-03-13 16:56 ` Jeffrey Carter 2013-03-13 17:09 ` Shark8 2013-03-13 17:32 ` Georg Bauhaus 1 sibling, 1 reply; 242+ messages in thread From: Jeffrey Carter @ 2013-03-13 16:56 UTC (permalink / raw) On 03/13/2013 08:51 AM, Dmitry A. Kazakov wrote: > > LRM is irrelevant here. The ARM is never irrelevant when discussing Ada. -- Jeff Carter "Ah, go away or I'll kill ya." Never Give a Sucker an Even Break 100 ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 16:56 ` Jeffrey Carter @ 2013-03-13 17:09 ` Shark8 0 siblings, 0 replies; 242+ messages in thread From: Shark8 @ 2013-03-13 17:09 UTC (permalink / raw) On Wednesday, March 13, 2013 10:56:27 AM UTC-6, Jeffrey Carter wrote: > On 03/13/2013 08:51 AM, Dmitry A. Kazakov wrote: > > > > > LRM is irrelevant here. > > The ARM is never irrelevant when discussing Ada. The only time the ARM could be irrelevant is when talking about "what ifs" like: * What if Red had won? * What if Ada 83 had child-packages? * What if Ada 95 had "abstract types"/"type classes" so you could define a truly generic string? (One base-type that could handle Character, Wide_Character, or Wide_Wide_Character.) ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 15:51 ` Dmitry A. Kazakov 2013-03-13 16:56 ` Jeffrey Carter @ 2013-03-13 17:32 ` Georg Bauhaus 2013-03-13 19:28 ` Dmitry A. Kazakov 1 sibling, 1 reply; 242+ messages in thread From: Georg Bauhaus @ 2013-03-13 17:32 UTC (permalink / raw) On 13.03.13 16:51, Dmitry A. Kazakov wrote: > LRM is irrelevant here. See The Ada LRM seems somewhat relevant when discussing the workings of Ada type attributes and predicates. > http://en.wikipedia.org/wiki/Abstract_data_type Ada subtypes are not ADTs. Which is the point. > Well, well, according to you Ada's Positive has -1 as a value? The Ada type of Positive includes -1 as a value. > How a type theory may not apply to a programming language? Anyway if you > don't like the theory X, you should propose another theory. Type as defined by the LRM; when the discussion is about how you dislike what subtypes are, fine. However, seeing how constraints and predicates work in Ada is not easier if by some twist of the discussion the explanation becomes one of how LSP and proper subsets create a well known problem in a hypothetical or otherwise non-Ada language that involves two different types, not Ada subtypes. Let "subtype" be an Ada subtype, nothing else, and everything becomes consistent again. Not necessarily clear, but consistent. Maybe confusing, but consistent. Maybe counterintuitive, but consistent. > But whichever theory you take, it cannot be consistent with Integer and > Positive being same type, while considering Ada typed. > > Ada is typed. Integer and Positive are not same. Not same what? Need a reference here. (There is an X such that grapefruits and oranges are not same X. There is an X such that Positive and Integer are not same X.) >> The difference only means that different range constraints yield >> different programs. > > The difference exists. q.e.d. You have shown that different constraints on objects of the same type yield different programs. But this is not q.e.d. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 17:32 ` Georg Bauhaus @ 2013-03-13 19:28 ` Dmitry A. Kazakov 2013-03-13 21:01 ` Randy Brukardt ` (2 more replies) 0 siblings, 3 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-13 19:28 UTC (permalink / raw) On Wed, 13 Mar 2013 18:32:01 +0100, Georg Bauhaus wrote: > On 13.03.13 16:51, Dmitry A. Kazakov wrote: > >> http://en.wikipedia.org/wiki/Abstract_data_type > > Ada subtypes are not ADTs. Which is the point. And the difference is? >> Well, well, according to you Ada's Positive has -1 as a value? > > The Ada type of Positive includes -1 as a value. This is where ARM becomes relevant again: ARM 3-2(8/2): "A subtype of a given type is a combination of the type, a constraint on values of the type, and certain attributes specific to the subtype. The given type is called the type of the subtype. Similarly, the associated constraint is called the constraint of the subtype." and the final blow: "The set of values of a subtype consists of the values of its type that satisfy its constraint and any exclusion of the null value. Such values belong to the subtype." >> How a type theory may not apply to a programming language? Anyway if you >> don't like the theory X, you should propose another theory. > > Type as defined by the LRM; when the discussion is about how > you dislike what subtypes are, fine. Where I said I dislike them? What I said is that Ada subtype is a type-algebraic operation that produces a new type which properties are described in ARM. There are other type algebraic operations which produce array, record types, tagged extension, class-wide types, generic expansions/instantiations etc. They all are used to construct new *types* from existing ones. > However, seeing how > constraints and predicates work in Ada is not easier if > by some twist of the discussion the explanation becomes one > of how LSP and proper subsets create a well known problem in > a hypothetical or otherwise non-Ada language that involves > two different types, not Ada subtypes. > Let "subtype" be an Ada subtype, nothing else, and everything > becomes consistent again. Not necessarily clear, but consistent. > Maybe confusing, but consistent. Maybe counterintuitive, but > consistent. You are welcome to show how problems of substitutability get solved without these explanations. 'Succ has the problem of substitutability because of these problems. It is due to multiple inheritance. Pred'Succ inherits some ordered interface from Integer and from its own problem space. 'Succ is an operation of the interfaces. These interfaces collide in Prime. Ada's design choice was in favor of Integer's order: 'Succ (3)=4. But user's expectation was the order from the problem space 'Succ(3)=5. Now whatever definitions you take the problem is there. It is not a problem of definitions. >> But whichever theory you take, it cannot be consistent with Integer and >> Positive being same type, while considering Ada typed. >> >> Ada is typed. Integer and Positive are not same. > > Not same what? Need a reference here. Use any name you want for the corresponding entities. Whatever name you choose, I am still able to construct a program which semantics would change when Integer is substituted by Positive. Positive is not always substitutable for Integer. However you re-write ARM, that fact is to stay. >>> The difference only means that different range constraints yield >>> different programs. >> >> The difference exists. q.e.d. > > You have shown that different constraints on objects of the > same type yield different programs. But this is not q.e.d. I shown that objects of Integer and Positive have different properties. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 19:28 ` Dmitry A. Kazakov @ 2013-03-13 21:01 ` Randy Brukardt 2013-03-13 21:18 ` Dmitry A. Kazakov 2013-03-13 21:37 ` Georg Bauhaus 2013-03-13 22:34 ` Robert A Duff 2 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-03-13 21:01 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:vxjicagtvzjg.1bcu3fzy711ux$.dlg@40tude.net... ... > What I said is that Ada subtype is a type-algebraic operation that > produces > a new type which properties are described in ARM. There are other type > algebraic operations which produce array, record types, tagged extension, > class-wide types, generic expansions/instantiations etc. They all are used > to construct new *types* from existing ones. A subtype does not create a new type, the quote you made from the RM says as much. QED :-) When talking about Ada, no one cares about abstract mis-definitions of the word "type" used by people who have no clue how to define a proper programming language. IMHO, Ada was the first language to get these things right (which I why I got professionally involved in Ada in the first place -- it was just a much better design than Pascal, C, or Modula, all of which I used before Ada). And ivory tower theories of programming language design are rarely worth the paper they're printed on -- it's not worth anyone's time to waste mental energy on that. You have many interesting ideas that would be far better served if you described them in Ada-terms. You're consistent refusal to do so means that they mostly get ignored -- and Ada (and programming in general) is all the poorer for it. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 21:01 ` Randy Brukardt @ 2013-03-13 21:18 ` Dmitry A. Kazakov 2013-03-14 21:51 ` Randy Brukardt 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-13 21:18 UTC (permalink / raw) On Wed, 13 Mar 2013 16:01:27 -0500, Randy Brukardt wrote: > You have many interesting ideas that would be far better served if you > described them in Ada-terms. How do you describe tagged types in Ada 83 terms? In order to move forward you need a consistent theory behind the language. RM is not the place where you could do that work. RM is about engineering, not science. You don't describe thermodynamic processes in terms of Volkswagen Owner's Manual. Thermodynamics apply both to VW and GM, regardless whatever manuals. If the car does not work, but the manual says it should, trust the car. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 21:18 ` Dmitry A. Kazakov @ 2013-03-14 21:51 ` Randy Brukardt 2013-03-15 1:10 ` Adam Beneschan 2013-03-15 9:20 ` Dmitry A. Kazakov 0 siblings, 2 replies; 242+ messages in thread From: Randy Brukardt @ 2013-03-14 21:51 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:13y3efy877tjl$.5yuu230sknnq$.dlg@40tude.net... > On Wed, 13 Mar 2013 16:01:27 -0500, Randy Brukardt wrote: > >> You have many interesting ideas that would be far better served if you >> described them in Ada-terms. > > How do you describe tagged types in Ada 83 terms? Why would I want to? Tagged types aren't part of Ada 83. In any case, only Ada 2012 plus fixes is relevant; everything else is buggier or incomplete. > In order to move forward you need a consistent theory behind the language. Right, and Ada has one explained in the RM. > RM is not the place where you could do that work. RM is about engineering, > not science. You don't describe thermodynamic processes in terms of > Volkswagen Owner's Manual. Thermodynamics apply both to VW and GM, > regardless whatever manuals. No one cares about that. You don't need to know about the laws of thermodynamics to operate a caase, and you don't need to know anything about type-algebras or other such baloney to program in a programming language. And it's the use of a programming language - not theories - that determines whether or not the language is truly usable. Another way to put it is that raw science (as you called it) is essentially irrelevant unless it can be applied to engineering. After all, *ideas* are worthless; only execution has value in today's world. I care about the execution (that is the usability of the design) of Ada, not how it fits into someone's theory of how things should be. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-14 21:51 ` Randy Brukardt @ 2013-03-15 1:10 ` Adam Beneschan 2013-03-15 21:22 ` Randy Brukardt 2013-03-15 9:20 ` Dmitry A. Kazakov 1 sibling, 1 reply; 242+ messages in thread From: Adam Beneschan @ 2013-03-15 1:10 UTC (permalink / raw) On Thursday, March 14, 2013 2:51:11 PM UTC-7, Randy Brukardt wrote: > No one cares about that. You don't need to know about the laws of > thermodynamics to operate a caase, Are you sure about this? Personally, I don't know how to operate a caase, and I couldn't find any instructions on the Internet about how to use a caase, or how to repair a caase, or for that matter even what a caase is. Sorry--I'm sure this is a typo but I can't figure out what you meant to say. :) > and you don't need to know anything about > type-algebras or other such baloney to program in a programming language. > And it's the use of a programming language - not theories - that determines > whether or not the language is truly usable. To my mind, the only reason to talk about abstract data types at all is that there are practical reasons why it's helpful for programmers to understand and think about them, and those practical reasons have to do with things like reusability, readability, and all that good stuff that helps us write correct programs and keep them correct. Programming language design involves trying to figure out what concepts, what syntaxes, etc., serve those goals. I don't see mathematics as being much help with this. The sciences that would help here seem to be more akin to psychology. -- Adam ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-15 1:10 ` Adam Beneschan @ 2013-03-15 21:22 ` Randy Brukardt 0 siblings, 0 replies; 242+ messages in thread From: Randy Brukardt @ 2013-03-15 21:22 UTC (permalink / raw) "Adam Beneschan" <adam@irvine.com> wrote in message news:927dfd51-e4b1-45af-9d51-57c167e84890@googlegroups.com... >On Thursday, March 14, 2013 2:51:11 PM UTC-7, Randy Brukardt wrote: > >> No one cares about that. You don't need to know about the laws of >> thermodynamics to operate a caase, > >Are you sure about this? Personally, I don't know how to operate a caase, >and I couldn't find any instructions on the >Internet about how to use a >caase, or how to repair a caase, or for that matter even what a caase is. > >Sorry--I'm sure this is a typo but I can't figure out what you meant to >say. :) The word was "car", and how it turned into "caase" will be an enduring mystery. >> and you don't need to know anything about >> type-algebras or other such baloney to program in a programming language. >> And it's the use of a programming language - not theories - that >> determines >> whether or not the language is truly usable. >To my mind, the only reason to talk about abstract data types at all is >that there are practical reasons >why it's helpful for programmers to understand and think about them, and >those practical reasons have >to do with things like reusability, readability, and all that good stuff >that helps us write correct programs >and keep them correct. Programming language design involves trying to >figure out what concepts, what >syntaxes, etc., serve those goals. I don't see mathematics as being much >help with this. The sciences >that would help here seem to be more akin to psychology. Exactly. Thanks for expanding on my point. Too many languages are designed based on theory rather than usability. Theory might be useful for academics to classify languages, but that's about it (and the value of that exercise is dubious). Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-14 21:51 ` Randy Brukardt 2013-03-15 1:10 ` Adam Beneschan @ 2013-03-15 9:20 ` Dmitry A. Kazakov 2013-03-15 21:43 ` Randy Brukardt 1 sibling, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-15 9:20 UTC (permalink / raw) On Thu, 14 Mar 2013 16:51:11 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:13y3efy877tjl$.5yuu230sknnq$.dlg@40tude.net... >> On Wed, 13 Mar 2013 16:01:27 -0500, Randy Brukardt wrote: >> >>> You have many interesting ideas that would be far better served if you >>> described them in Ada-terms. >> >> How do you describe tagged types in Ada 83 terms? > > Why would I want to? You insisted on that claiming that Ada can be only discussed in Ada-terms. >> RM is not the place where you could do that work. RM is about engineering, >> not science. You don't describe thermodynamic processes in terms of >> Volkswagen Owner's Manual. Thermodynamics apply both to VW and GM, >> regardless whatever manuals. > > No one cares about that. People building cars do. >You don't need to know about the laws of > thermodynamics to operate a caase, Until it works as expected, yes. But if you wonder why your car consumes gas rather than produces it, you should turn to thermodynamics. > Another way to put it is that raw science (as you called it) is essentially > irrelevant unless it can be applied to engineering. After all, *ideas* are > worthless; only execution has value in today's world. I care about the > execution (that is the usability of the design) of Ada, not how it fits into > someone's theory of how things should be. Then you must have wrong understanding of science. It is actually the reverse: if the theory does not explain facts, it is wrong. Ada's subtype as defined by RM is a fact to explain (and to predict consequences of the choices made). The theory does it quite well. The rant about how Ada's RM names its subtypes is absolutely irrelevant. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-15 9:20 ` Dmitry A. Kazakov @ 2013-03-15 21:43 ` Randy Brukardt 2013-03-16 7:56 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-03-15 21:43 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:1xsmzl7alqflb$.oz1qkrleisa7$.dlg@40tude.net... > On Thu, 14 Mar 2013 16:51:11 -0500, Randy Brukardt wrote: > >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >> news:13y3efy877tjl$.5yuu230sknnq$.dlg@40tude.net... >>> On Wed, 13 Mar 2013 16:01:27 -0500, Randy Brukardt wrote: >>> >>>> You have many interesting ideas that would be far better served if you >>>> described them in Ada-terms. >>> >>> How do you describe tagged types in Ada 83 terms? >> >> Why would I want to? > > You insisted on that claiming that Ada can be only discussed in Ada-terms. You didn't answer the question. Why would you want to describe something from a recent version of the language in terms of an obsolete one? On top of which, when anyone says Ada without qualification, that means Ada 2012 (as that is the current version of Ada). I'm not likely to talk about Ada 83 as there is no point (of course, for many things, the language version doesn't matter). ... >> Another way to put it is that raw science (as you called it) is >> essentially >> irrelevant unless it can be applied to engineering. After all, *ideas* >> are >> worthless; only execution has value in today's world. I care about the >> execution (that is the usability of the design) of Ada, not how it fits >> into >> someone's theory of how things should be. > > Then you must have wrong understanding of science. It is actually the > reverse: if the theory does not explain facts, it is wrong. Huh? I'm contending that the theory is irrelevant (much like religion -- and it shares a lot of characteristics with that). That's because you can't use it to design a useful programming language, only to pigeon-hole and/or take potshots at it after the fact. That's not useful or helpful. One could say that about a lot of basic theories. Knowledge of thermodynamics has little to do with designing an engine; you need a lot of knowledge about other things to do that, and thermodynamics is *way* down on the list of things that matter. After all those rules are very simple to paraphrase: "You can't win the game. You can't break even. And you can't quit the game." And you can't do much even knowing that. > Ada's subtype as defined by RM is a fact to explain (and to predict > consequences of the choices made). The theory does it quite well. The rant > about how Ada's RM names its subtypes is absolutely irrelevant. But no one cares, because such matching has no relevance to anything: it's not going to change the design of Ada (compatibility concerns would prevent that in any case) and nothing about it would help you be a better Ada programmer (especially as the terminology clash makes it close to impossible to think about one and make sense of the other). So it is a waste of time. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-15 21:43 ` Randy Brukardt @ 2013-03-16 7:56 ` Dmitry A. Kazakov 2013-03-18 22:52 ` Randy Brukardt 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-16 7:56 UTC (permalink / raw) On Fri, 15 Mar 2013 16:43:47 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:1xsmzl7alqflb$.oz1qkrleisa7$.dlg@40tude.net... >> On Thu, 14 Mar 2013 16:51:11 -0500, Randy Brukardt wrote: >> >>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >>> news:13y3efy877tjl$.5yuu230sknnq$.dlg@40tude.net... >>>> On Wed, 13 Mar 2013 16:01:27 -0500, Randy Brukardt wrote: >>>> >>>>> You have many interesting ideas that would be far better served if you >>>>> described them in Ada-terms. >>>> >>>> How do you describe tagged types in Ada 83 terms? >>> >>> Why would I want to? >> >> You insisted on that claiming that Ada can be only discussed in Ada-terms. > > You didn't answer the question. Why would you want to describe something > from a recent version of the language in terms of an obsolete one? To illustrate the point that one cannot extend/modify the language discussing it in its terms, like baron Munchausen pulling yourself out of a swamp by your hair. How would you tell yourself from year 1992 about Ada 95? The other you would not listen to you. >>> Another way to put it is that raw science (as you called it) is essentially >>> irrelevant unless it can be applied to engineering. After all, *ideas* are >>> worthless; only execution has value in today's world. I care about the >>> execution (that is the usability of the design) of Ada, not how it fits into >>> someone's theory of how things should be. >> >> Then you must have wrong understanding of science. It is actually the >> reverse: if the theory does not explain facts, it is wrong. > > Huh? I'm contending that the theory is irrelevant (much like religion -- and > it shares a lot of characteristics with that). That's because you can't use > it to design a useful programming language, only to pigeon-hole and/or take > potshots at it after the fact. That's not useful or helpful. > > One could say that about a lot of basic theories. Knowledge of > thermodynamics has little to do with designing an engine; you need a lot of > knowledge about other things to do that, and thermodynamics is *way* down on > the list of things that matter. Not at all. Other things are relevant only in the context of more fundamental laws like thermodynamics. In engineering you must know, at least in theory, how to deduce any specialized rule from fundamental laws. This is what differentiates proper science and engineering from junk like economics or climatology. Granted, CS is somewhere in between. >> Ada's subtype as defined by RM is a fact to explain (and to predict >> consequences of the choices made). The theory does it quite well. The rant >> about how Ada's RM names its subtypes is absolutely irrelevant. > > But no one cares, because such matching has no relevance to anything: it's > not going to change the design of Ada (compatibility concerns would prevent > that in any case) There is no compatibility concerns. Robert said in this thread that Prime'Range, Prime'First, Prime'Last are all illegal. So it is already incompatible, if under compatibility you understand that a subtype must inherit everything. > and nothing about it would help you be a better Ada > programmer (especially as the terminology clash makes it close to impossible > to think about one and make sense of the other). On the contrary, understanding that a subtype is a type with values and operation helps a lot. Especially when it comes to aberrations like with Prime'Succ. It is an operation of Prime and the programmer should know that in Ada he has no influence on its implementation which is always inherited from the base type. If that does not correspond his intent he must change the design and use other means, e.g. tagged types or unrelated types (derive Prime privately). -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-16 7:56 ` Dmitry A. Kazakov @ 2013-03-18 22:52 ` Randy Brukardt 2013-03-19 10:32 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-03-18 22:52 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:a9ivriefwvbm.1mwi80nz4jz6h$.dlg@40tude.net... > On Fri, 15 Mar 2013 16:43:47 -0500, Randy Brukardt wrote: > >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >> news:1xsmzl7alqflb$.oz1qkrleisa7$.dlg@40tude.net... >>> On Thu, 14 Mar 2013 16:51:11 -0500, Randy Brukardt wrote: >>> >>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >>>> news:13y3efy877tjl$.5yuu230sknnq$.dlg@40tude.net... ... >>>>> How do you describe tagged types in Ada 83 terms? >>>> >>>> Why would I want to? >>> >>> You insisted on that claiming that Ada can be only discussed in >>> Ada-terms. >> >> You didn't answer the question. Why would you want to describe something >> from a recent version of the language in terms of an obsolete one? > > To illustrate the point that one cannot extend/modify the language > discussing it in its terms, like baron Munchausen pulling yourself out of > a > swamp by your hair. We're not talking about extending or modifying the language, so that would not be relevant. > How would you tell yourself from year 1992 about Ada 95? The other you > would not listen to you. Well, in 1992, we were already working on implementation Ada 9x (which became Ada 95), as we were part of one of the user/implementer teams. So it wouldn't be hard at all to do. :-) And Ada 9x was described in terms of extending existing Ada concepts, so it wasn't that hard to understand at all. ... >>> Ada's subtype as defined by RM is a fact to explain (and to predict >>> consequences of the choices made). The theory does it quite well. The >>> rant >>> about how Ada's RM names its subtypes is absolutely irrelevant. >> >> But no one cares, because such matching has no relevance to anything: >> it's >> not going to change the design of Ada (compatibility concerns would >> prevent >> that in any case) > > There is no compatibility concerns. Robert said in this thread that > Prime'Range, Prime'First, Prime'Last are all illegal. So it is already > incompatible, if under compatibility you understand that a subtype must > inherit everything. Huh? In this content, "Compatibility" means new versions of Ada should not break existing Ada code. For the definition of 'Succ, for example, we cannot change it without potentially breaking existing code, so it is unlikely that we would make such a change. >> and nothing about it would help you be a better Ada >> programmer (especially as the terminology clash makes it close to >> impossible >> to think about one and make sense of the other). > > On the contrary, understanding that a subtype is a type with values and > operation helps a lot. Especially when it comes to aberrations like with > Prime'Succ. It is an operation of Prime and the programmer should know > that > in Ada he has no influence on its implementation which is always inherited > from the base type. If that does not correspond his intent he must change > the design and use other means, e.g. tagged types or unrelated types > (derive Prime privately). You seem to get the right conclusion from the wrong premise. If you understand that Positive is not a type, but rather *has* a type, and operations are chosen based on the type that Positive has (not by the subtype), then the behavior of 'Succ makes perfect sense, because its the same behavior that you get for "+" and "*" and all of the other predefined operations. Prime'Succ is thus an operation of Integer'Base (as subtypes like Prime don't have operations), and clearly how it behaves is based on that. And yes, if you want some other behavior, then you have to write it yourself -- nothing new about that. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-18 22:52 ` Randy Brukardt @ 2013-03-19 10:32 ` Dmitry A. Kazakov 0 siblings, 0 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-19 10:32 UTC (permalink / raw) On Mon, 18 Mar 2013 17:52:03 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:a9ivriefwvbm.1mwi80nz4jz6h$.dlg@40tude.net... >> On Fri, 15 Mar 2013 16:43:47 -0500, Randy Brukardt wrote: >> >>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >>> news:1xsmzl7alqflb$.oz1qkrleisa7$.dlg@40tude.net... >>>> On Thu, 14 Mar 2013 16:51:11 -0500, Randy Brukardt wrote: >>>> >>>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >>>>> news:13y3efy877tjl$.5yuu230sknnq$.dlg@40tude.net... > ... >>>>>> How do you describe tagged types in Ada 83 terms? >>>>> >>>>> Why would I want to? >>>> >>>> You insisted on that claiming that Ada can be only discussed in >>>> Ada-terms. >>> >>> You didn't answer the question. Why would you want to describe something >>> from a recent version of the language in terms of an obsolete one? >> >> To illustrate the point that one cannot extend/modify the language >> discussing it in its terms, like baron Munchausen pulling yourself out of >> a swamp by your hair. > > We're not talking about extending or modifying the language, so that would > not be relevant. It is the same context though. >>>> Ada's subtype as defined by RM is a fact to explain (and to predict >>>> consequences of the choices made). The theory does it quite well. The rant >>>> about how Ada's RM names its subtypes is absolutely irrelevant. >>> >>> But no one cares, because such matching has no relevance to anything: it's >>> not going to change the design of Ada (compatibility concerns would prevent >>> that in any case) >> >> There is no compatibility concerns. Robert said in this thread that >> Prime'Range, Prime'First, Prime'Last are all illegal. So it is already >> incompatible, if under compatibility you understand that a subtype must >> inherit everything. > > Huh? In this content, "Compatibility" means new versions of Ada should not > break existing Ada code. For the definition of 'Succ, for example, we cannot > change it without potentially breaking existing code, so it is unlikely that > we would make such a change. Of course you can do it without breaking anything. Making an operation primitive and allowing it to be overridden, can break nothing. But actually S'Succ (X) shall go straight to the section J. We should introduce X'Succ, a primitive operation of the interface Ordered and forget about the mess. Instead of deriving Prime from Integer and inheriting what should not be there, you would do from Copyable, add user-defined literals (=inherit some integer literals, which are functions, of course), and privately implement it as Integer. >>> and nothing about it would help you be a better Ada >>> programmer (especially as the terminology clash makes it close to >>> impossible to think about one and make sense of the other). >> >> On the contrary, understanding that a subtype is a type with values and >> operation helps a lot. Especially when it comes to aberrations like with >> Prime'Succ. It is an operation of Prime and the programmer should know that >> in Ada he has no influence on its implementation which is always inherited >> from the base type. If that does not correspond his intent he must change >> the design and use other means, e.g. tagged types or unrelated types >> (derive Prime privately). > > You seem to get the right conclusion from the wrong premise. So, the theory works. > If you > understand that Positive is not a type, but rather *has* a type, and > operations are chosen based on the type that Positive has (not by the > subtype), then the behavior of 'Succ makes perfect sense, because its the > same behavior that you get for "+" and "*" and all of the other predefined > operations. No, it does not make sense, because the semantics of Prime is not defined by RM, it is in the realm of mathematics. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 19:28 ` Dmitry A. Kazakov 2013-03-13 21:01 ` Randy Brukardt @ 2013-03-13 21:37 ` Georg Bauhaus 2013-03-14 11:18 ` Dmitry A. Kazakov 2013-03-13 22:34 ` Robert A Duff 2 siblings, 1 reply; 242+ messages in thread From: Georg Bauhaus @ 2013-03-13 21:37 UTC (permalink / raw) On 13.03.13 20:28, Dmitry A. Kazakov wrote: >> Ada subtypes are not ADTs. Which is the point. > > And the difference is? Several: Incomparable. In Ada, ADT is not defined. An ADT is a model of thought that can be mapped to constructs. I find it moderately useful to insist on problems with predicates that only exist in the ADT/LSP model, but not in Ada (where there simply is no variance in this case due to the definition of 'Succ). >>> Well, well, according to you Ada's Positive has -1 as a value? >> >> The Ada type of Positive includes -1 as a value. > > This is where ARM becomes relevant again: > > ARM 3-2(8/2): ARM 3.2(8/2) implies that "the type of Positive includes the value -1" (the type of Positive is not the subtype Positive). For example, with one compiler, values_of(Positive) = { x : x ∈ values_of(type_of(Positive)) | x ≧ 1 & x ≦ 2³¹-1 } The paragraph you have quoted from the LRM thus indicates that the value -1 belongs to the type of Positive, but -1 does not belong to what Ada calls a subtype. Hence, again, the type of Positive includes the value -1, but the subtype Positive does not. Let me see if I understand the claim that a subtype declarations is a type-algebraic operation correctly, with Ada in mind: One starts from types to produce new types. type V is array (S) of T; declares a new type (and its ...). But subtype V is Integer range -2 .. +34; does not declare a new type (LRM 3.2.2(1)). Only some re-interpretation of Ada terms creates a notion of subtype that Ada does not seem to support, really. One can do this, but when solving a problem with (a misreading of) 'Succ, doing so only emphasizes the cause of the problem, which is assuming that a subtype can be treated the same way as a type or ADT. > You are welcome to show how problems of substitutability get solved without > these explanations. There is no substitutability issue whatsoever for parameters of 'Succ because 'Succ is not defined in terms of types that could introduce the problem. This definition may not be as desired, but the problem is extraneous from an Ada perspective. Instead, I could define (like you have done many times before): type T is private ...; function Succ (X : T) return T with ...; when I need to map T to an algebraic data type. > It is not a problem of definitions. Is it *solely* a problem of definitions from the non-Ada world. > I shown that objects of Integer and Positive have different properties. The difference is entirely a consequence of different constraints on the same type that Integer and Positive share. I wondered why you have avoided the word "type" here and use "properties" instead? ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 21:37 ` Georg Bauhaus @ 2013-03-14 11:18 ` Dmitry A. Kazakov 2013-03-14 12:37 ` Georg Bauhaus 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-14 11:18 UTC (permalink / raw) On Wed, 13 Mar 2013 22:37:49 +0100, Georg Bauhaus wrote: > On 13.03.13 20:28, Dmitry A. Kazakov wrote: > >>> Ada subtypes are not ADTs. Which is the point. >> >> And the difference is? > > Several: > Incomparable. > In Ada, ADT is not defined. How exactly Ada's Positive is not an abstract data type? >>>> Well, well, according to you Ada's Positive has -1 as a value? >>> >>> The Ada type of Positive includes -1 as a value. >> >> This is where ARM becomes relevant again: >> >> ARM 3-2(8/2): > > ARM 3.2(8/2) implies that "the type of Positive includes the value -1" > (the type of Positive is not the subtype Positive). We don't talk about Positive'Base. We do about Positive. > Let me see if I understand the claim that a subtype declarations is > a type-algebraic operation correctly, with Ada in mind: > > One starts from types to produce new types. > > type V is array (S) of T; > > declares a new type (and its ...). But > > subtype V is Integer range -2 .. +34; > > does not declare a new type (LRM 3.2.2(1)). Nevertheless Positive'Base /= Positive and both are types. >> You are welcome to show how problems of substitutability get solved without >> these explanations. > > There is no substitutability issue whatsoever for parameters of 'Succ > because 'Succ is not defined in terms of types that could introduce the > problem. I don't understand. What is defined, in which terms, what introduces or not problems? > This definition may not be as desired, Definition of what? >> It is not a problem of definitions. > > Is it *solely* a problem of definitions from the non-Ada world. So, it is prime numbers which are broken. Good to know... >> I shown that objects of Integer and Positive have different properties. > > The difference is entirely a consequence of different constraints on the > same type that Integer and Positive share. Irrelevant. The difference is here. Period. > I wondered why you have avoided the word "type" here and use "properties" > instead? You objected the word type. Call it "task" if you want to. It is still not Integer. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-14 11:18 ` Dmitry A. Kazakov @ 2013-03-14 12:37 ` Georg Bauhaus 2013-03-14 14:26 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Georg Bauhaus @ 2013-03-14 12:37 UTC (permalink / raw) On 14.03.13 12:18, Dmitry A. Kazakov wrote: > On Wed, 13 Mar 2013 22:37:49 +0100, Georg Bauhaus wrote: > >> On 13.03.13 20:28, Dmitry A. Kazakov wrote: >> >>>> Ada subtypes are not ADTs. Which is the point. >>> >>> And the difference is? >> >> Several: >> Incomparable. >> In Ada, ADT is not defined. > > How exactly Ada's Positive is not an abstract data type? Because ADTs are constructs of human mapping from a model space to the space of language constructs. In this case the latter is defined in Ada terms. The human's mapping activity causes the---legitimate--- problem with subtype constraints. > We don't talk about Positive'Base. We do about Positive. Positive'Succ does *not* declare parameters whose subtype is Positive. This fact answers most of the other comments, I should think. For a start, LRM 3.5 again, 22 S'Succ S'Succ denotes a function with the following specification: 23 function S'Succ(Arg : S'Base) return S'Base We don't talk about Positive'Base, you say? >> subtype V is Integer range -2 .. +34; >> >> does not declare a new type (LRM 3.2.2(1)). > > Nevertheless > > Positive'Base /= Positive > > and both are types. The second claim is not true in Ada as relevant to this discussion, because Positive's subtype constraint does not introduce a type. >>> It is not a problem of definitions. >> >> Is it *solely* a problem of definitions from the non-Ada world. > > So, it is prime numbers which are broken. Good to know... Prime numbers are not defined in Ada, so the definition of Ada cannot break them. The subtype named Prime that was given was essentially a constraining predicate. If anyone thinks that 'Succ can be re-interpreted to refer to a non-interval subset of integral numbers of an Ada type, and it can't, then that's the problem: A plausible assumption about the definition vs the actual definition. >>> I shown that objects of Integer and Positive have different properties. >> >> The difference is entirely a consequence of different constraints on the >> same type that Integer and Positive share. > > Irrelevant. The difference is here. Period. It is proof that Ada subtypes (not Ada types) and LSP (plus, in this case, a re-interpretation of 'Succ based on incorrect premises) causes problems with constraints (not types). The compiler does not reject x : Positive := -1, so there is no Ada typing problem. There are two problems instead: 1) to think that a subtype creates a type 2) to assume that 'Succ is not what it is ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-14 12:37 ` Georg Bauhaus @ 2013-03-14 14:26 ` Dmitry A. Kazakov 2013-03-14 14:57 ` Georg Bauhaus ` (2 more replies) 0 siblings, 3 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-14 14:26 UTC (permalink / raw) On Thu, 14 Mar 2013 13:37:44 +0100, Georg Bauhaus wrote: >> How exactly Ada's Positive is not an abstract data type? > > Because ADTs are constructs of human mapping from a model space to the > space of language constructs. In this case the latter is defined in Ada > terms. That does not answer the question. ADT is a set of values and operations. Please, show how Positive is different from that. >> We don't talk about Positive'Base. We do about Positive. > > Positive'Succ does *not* declare parameters whose subtype is Positive. Surely it does. Proof: X : Positive := 1; Y : Positive := Positive'Succ (X); Either Ada is untyped or else Positive'Succ is effectively defined on Positive and returns Positive. > 22 S'Succ S'Succ denotes a function with the following specification: > > 23 function S'Succ(Arg : S'Base) > return S'Base > > We don't talk about Positive'Base, you say? Yes, since the language allows usage Positive with Positive'Succ that automatically means that Positive has this operation. >>> subtype V is Integer range -2 .. +34; >>> >>> does not declare a new type (LRM 3.2.2(1)). >> >> Nevertheless >> >> Positive'Base /= Positive >> >> and both are types. > > The second claim is not true in Ada as relevant to this discussion, > because Positive's subtype constraint does not introduce a type. Any set of values and operations introduces an abstract data type per definition of. Compare: C++ reference manual uses the term "class" for what is ADT. That does not make C++ classes non-types. They still are. >>>> It is not a problem of definitions. >>> >>> Is it *solely* a problem of definitions from the non-Ada world. >> >> So, it is prime numbers which are broken. Good to know... > > Prime numbers are not defined in Ada, so the definition of Ada cannot > break them. The subtype named Prime that was given was essentially a > constraining predicate. If anyone thinks that 'Succ can be > re-interpreted to refer to a non-interval subset of integral numbers > of an Ada type, and it can't, then that's the problem: A plausible > assumption about the definition vs the actual definition. That is a language problem. Dynamic predicates will be seen, felt and used as abstract data types. This is why they should not be there. They effectively make the language typing weaker. And they are against the core Ada design idea that any implicit choice must be safe and any unsafe choice explicit. Inheritance of 'Succ is unsafe for certain types of constraints. > There are two problems instead: > > 1) to think that a subtype creates a type It certainly does. Positive /= Integer and the inequality here is in Ada terms. > 2) to assume that 'Succ is not what it is Exactly, ARM assumed something about programmer's intentions regarding the subtype Prime and failed miserably. So did PL/1 with its ad-hoc type conversions. Ada designers knew all that in 80's. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-14 14:26 ` Dmitry A. Kazakov @ 2013-03-14 14:57 ` Georg Bauhaus 2013-03-14 15:51 ` Anh Vo 2013-03-14 16:21 ` J-P. Rosen 2013-03-14 16:22 ` Shark8 2 siblings, 1 reply; 242+ messages in thread From: Georg Bauhaus @ 2013-03-14 14:57 UTC (permalink / raw) On 14.03.13 15:26, Dmitry A. Kazakov wrote: > Dynamic predicates will be seen, felt and used > as abstract data types Well put, and this can put an end to a discussion based on nothing but a lexical ambiguity of "type". ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-14 14:57 ` Georg Bauhaus @ 2013-03-14 15:51 ` Anh Vo 0 siblings, 0 replies; 242+ messages in thread From: Anh Vo @ 2013-03-14 15:51 UTC (permalink / raw) On Thursday, March 14, 2013 7:57:18 AM UTC-7, Georg Bauhaus wrote: > On 14.03.13 15:26, Dmitry A. Kazakov wrote: > Dynamic predicates will be seen, felt and used > as abstract data types Well put, and this can put an end to a discussion based on nothing but a lexical ambiguity of "type". I am hesitate to chime in since the discussion was way over my head. Back to my original question, I have found another way to accomplish my task. Thank you all for your input. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-14 14:26 ` Dmitry A. Kazakov 2013-03-14 14:57 ` Georg Bauhaus @ 2013-03-14 16:21 ` J-P. Rosen 2013-03-14 17:29 ` Dmitry A. Kazakov 2013-03-14 16:22 ` Shark8 2 siblings, 1 reply; 242+ messages in thread From: J-P. Rosen @ 2013-03-14 16:21 UTC (permalink / raw) Le 14/03/2013 15:26, Dmitry A. Kazakov a �crit : >> Because ADTs are constructs of human mapping from a model space to the >> > space of language constructs. In this case the latter is defined in Ada >> > terms. > That does not answer the question. ADT is a set of values and operations. > Please, show how Positive is different from that. > The set of values is not defined by Positive, it is defined by Integer. Positive is a name to designate a subset of these values. >> There are two problems instead: >> >> 1) to think that a subtype creates a type > > It certainly does. Positive /= Integer and the inequality here is in Ada > terms. > Ada allows assignment only if both sides are of the same type. You can assign Integer to Positive, and conversely. Therefore, Positive and Integer are the same type. qed. And please, we are talking about Ada here, not KOVOA (Kasakov's Own View of Ada). -- J-P. Rosen Adalog 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00 http://www.adalog.fr ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-14 16:21 ` J-P. Rosen @ 2013-03-14 17:29 ` Dmitry A. Kazakov 2013-03-14 18:16 ` Georg Bauhaus 2013-03-14 22:12 ` Randy Brukardt 0 siblings, 2 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-14 17:29 UTC (permalink / raw) On Thu, 14 Mar 2013 17:21:23 +0100, J-P. Rosen wrote: > Le 14/03/2013 15:26, Dmitry A. Kazakov a �crit : >>> Because ADTs are constructs of human mapping from a model space to the >>> > space of language constructs. In this case the latter is defined in Ada >>> > terms. >> That does not answer the question. ADT is a set of values and operations. >> Please, show how Positive is different from that. >> > The set of values is not defined by Positive, it is defined by Integer. Still, Positive has values, and operations. > Positive is a name to designate a subset of these values. And Integer is a name to designate a subset of Z. And Z is a subset of R or Q. And R is a subset of C. Why does it matter? >>> There are two problems instead: >>> >>> 1) to think that a subtype creates a type >> >> It certainly does. Positive /= Integer and the inequality here is in Ada >> terms. >> > Ada allows assignment only if both sides are of the same type. You can > assign Integer to Positive, and conversely. Therefore, Positive and > Integer are the same type. You forgot other possibilities: 1. The premise is wrong. It is, Ada indeed allows assignment of different types. Example: type T is tagged null record; X : T'Class := T'(null record); I hope you will not claim that T'Class and T are the same type. 2. Assignment is a primitive operation of the corresponding class of related types which effectively permits profiles like: procedure ":=" (Left : in out Integer; Right : Integer); procedure ":=" (Left : in out Positive; Right : Integer); procedure ":=" (Left : in out Integer; Right : Positive); procedure ":=" (Left : in out Positive; Right : Positive); Observe that in Ada these bodies are different. E.g. the second may raise Constraint_Error. I didn't say that Positive is unrelated to Integer type. It is a subtype of. Yet it is a distinct type with a set of values and a set of operations. In order to be "sub-something" you must be "something" first. > And please, we are talking about Ada here, not KOVOA (Kasakov's Own View > of Ada). Yes, it is my view of Ada. You have yours. What is wrong with that? -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-14 17:29 ` Dmitry A. Kazakov @ 2013-03-14 18:16 ` Georg Bauhaus 2013-03-15 9:33 ` Dmitry A. Kazakov 2013-03-14 22:12 ` Randy Brukardt 1 sibling, 1 reply; 242+ messages in thread From: Georg Bauhaus @ 2013-03-14 18:16 UTC (permalink / raw) On 14.03.13 18:29, Dmitry A. Kazakov wrote: >> > And please, we are talking about Ada here, not KOVOA (Kasakov's Own View >> > of Ada). > Yes, it is my view of Ada. You have yours. What is wrong with that? An analogy: The language C is an O-O language because the following is both standard conforming and consistent with ADT views of C: Convert a void* to a struct that has a vtbl-Pointer that points to another struct (equally convertible from void*) that has a function pointer. Everything is type checked. This construct allows everything one needs in O-O programming. The programs following this view exhibit a view of C as a language whose structs obviously create inheritable O-O types that have operations, all in the sense of perfect ADTs. C is clearly an O-O language, then, since you can observe the behavior of such programs to be O-O. This style of argument will challenge other views of C in the style of a provocation that requires much work to set straight. Maybe the time is better spent on outlining the addition of abstract scalar types to Ada? ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-14 18:16 ` Georg Bauhaus @ 2013-03-15 9:33 ` Dmitry A. Kazakov 2013-03-15 10:05 ` Georg Bauhaus 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-15 9:33 UTC (permalink / raw) On Thu, 14 Mar 2013 19:16:35 +0100, Georg Bauhaus wrote: > On 14.03.13 18:29, Dmitry A. Kazakov wrote: >>> > And please, we are talking about Ada here, not KOVOA (Kasakov's Own View >>> > of Ada). >> Yes, it is my view of Ada. You have yours. What is wrong with that? > > An analogy: [...] You are confusing program with the language of. You can write a program in OOA/D-way in any language, Assembler included. That does not make those languages OOPL. OOA/D /= OOPL OOPL supports certain kinds of ADT's at the language level. There is no agreed definition but usually support of dynamic polymorphism (=sets of ADT's and ADT representing these sets) is considered necessary for a language to be considered OO. Ada 95+ is an OOPL according to this definition, because Ada directly supports sets of types (Ada's class) and has types representing instances from set members (class-wide types). -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-15 9:33 ` Dmitry A. Kazakov @ 2013-03-15 10:05 ` Georg Bauhaus 2013-03-15 11:15 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Georg Bauhaus @ 2013-03-15 10:05 UTC (permalink / raw) On 15.03.13 10:33, Dmitry A. Kazakov wrote: > On Thu, 14 Mar 2013 19:16:35 +0100, Georg Bauhaus wrote: > >> On 14.03.13 18:29, Dmitry A. Kazakov wrote: >>>>> And please, we are talking about Ada here, not KOVOA (Kasakov's Own View >>>>> of Ada). >>> Yes, it is my view of Ada. You have yours. What is wrong with that? >> >> An analogy: > [...] > > You are confusing program with the language of. I did chose this confused view to demonstrate what will be the effect of confusing subtype constraints (or not, as in 'Succ) and types in the sense everyone here is supposed to approach the word "type". Except when indicated. Ada is then not a typed LSP language at the level of subtype constraints and attributes of types. Make it such a language, make it convincing, and define a model that can be turned into Ada language definitions. But, please, mark those phrases that say "problem" as "problem if 'Succ is viewed as a function that is different from how it is defined" in the universe of c.l.ada, but could be defined if 'Succ were an operation of a subtype turned ADT (which it isn't, in Ada). > OOPL supports certain kinds of ADT's at the language level. Right. At the language level, Ada does not support certain kinds of LSP at the subtype level (well), Ada does not support equating types and subtypes, and Ada does not support equating ADTs and type with all attributes. Because type /= subtype, here, at the language level. That's why I had chosen the OOP view of C. It's not an OOP at the language level. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-15 10:05 ` Georg Bauhaus @ 2013-03-15 11:15 ` Dmitry A. Kazakov 0 siblings, 0 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-15 11:15 UTC (permalink / raw) On Fri, 15 Mar 2013 11:05:39 +0100, Georg Bauhaus wrote: > I did chose this confused view to demonstrate what will be the > effect of confusing subtype constraints (or not, as in 'Succ) > and types in the sense everyone here is supposed to approach > the word "type". Except when indicated. I already addressed this. When type+constraint is not considered a type the language becomes weakly typed. Note also that any language, even untyped, can be attributed with types. And programmers think in terms of types even if the language does not allow to articulate these types in language terms. Ada's strength, e.g. comparing to C, is in allowing to articulate types and their relationships (e.g. subtypes) rather than leaving them to reader's imagination. > Ada is then not a typed LSP language at the level of subtype constraints > and attributes of types. Make it such a language, make it convincing, > and define a model that can be turned into Ada language definitions. You are confusing LSP with typing. LSP is much less than typing in general. Ada subtype is not an LSP-subtype, yet both Ada- and LSP-subtypes are types. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-14 17:29 ` Dmitry A. Kazakov 2013-03-14 18:16 ` Georg Bauhaus @ 2013-03-14 22:12 ` Randy Brukardt 2013-03-15 9:46 ` Dmitry A. Kazakov [not found] ` <ewe0v3ck1xdo$.e8rtuof27ke6$.dlg@40tude.net > 1 sibling, 2 replies; 242+ messages in thread From: Randy Brukardt @ 2013-03-14 22:12 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:1wv3p3nrtejfk$.bwebhg9agt0l.dlg@40tude.net... > On Thu, 14 Mar 2013 17:21:23 +0100, J-P. Rosen wrote: ... >> The set of values is not defined by Positive, it is defined by Integer. > > Still, Positive has values, and operations. Yes, and they're exactly the same set as Integer has. The values and operations of a type determine what is statically allowed (that is, what is legal). And for the purposes of legality, Integer and Positive are exactly the same. There are some differences in *dynamic* behavior, but that has nothing to do with the available values and operations. (The text you quoted from the RM about values "belonging" to a subtype is defining dynamic behavior.) I recall some Dmitry guy telling us that dynamic behavior is different from static behavior, and even claiming that dynamic behavior cannot constitute a contract. So it if is not a *contract*, how come it matters for a *type* (which is an integral part of describing a contract)? Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-14 22:12 ` Randy Brukardt @ 2013-03-15 9:46 ` Dmitry A. Kazakov [not found] ` <ewe0v3ck1xdo$.e8rtuof27ke6$.dlg@40tude.net > 1 sibling, 0 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-15 9:46 UTC (permalink / raw) On Thu, 14 Mar 2013 17:12:28 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:1wv3p3nrtejfk$.bwebhg9agt0l.dlg@40tude.net... >> On Thu, 14 Mar 2013 17:21:23 +0100, J-P. Rosen wrote: > ... >>> The set of values is not defined by Positive, it is defined by Integer. >> >> Still, Positive has values, and operations. > > Yes, and they're exactly the same set as Integer has. Even so, having those makes it an ADT. For the sake of argument consider subtype Integer_X is Integer; Both are ADTs. BTW, a renaming would be the thing you are talking about. But Ada does not have type renaming. People [mis]using subtypes for the purpose of renaming must be prepared to nasty surprises. > There are some differences in *dynamic* behavior, but that has nothing to do > with the available values and operations. (The text you quoted from the RM > about values "belonging" to a subtype is defining dynamic behavior.) I > recall some Dmitry guy telling us that dynamic behavior is different from > static behavior, and even claiming that dynamic behavior cannot constitute a > contract. So it if is not a *contract*, how come it matters for a *type* > (which is an integral part of describing a contract)? I don't understand the point you are making. You cannot derive contract from behavior, simply because it is converse: contract is imposed to restrain possible behaviors. You might claim that implied contracts of Integer and Positive are exactly same. I doubt that many would agree with that. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
[parent not found: <ewe0v3ck1xdo$.e8rtuof27ke6$.dlg@40tude.net >]
* Re: Is this expected behavior or not [not found] ` <ewe0v3ck1xdo$.e8rtuof27ke6$.dlg@40tude.net > @ 2013-03-15 21:17 ` Randy Brukardt 2013-03-16 7:51 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-03-15 21:17 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:ewe0v3ck1xdo$.e8rtuof27ke6$.dlg@40tude.net... > On Thu, 14 Mar 2013 17:12:28 -0500, Randy Brukardt wrote: > >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >> news:1wv3p3nrtejfk$.bwebhg9agt0l.dlg@40tude.net... >>> On Thu, 14 Mar 2013 17:21:23 +0100, J-P. Rosen wrote: >> ... >>>> The set of values is not defined by Positive, it is defined by Integer. >>> >>> Still, Positive has values, and operations. >> >> Yes, and they're exactly the same set as Integer has. > > Even so, having those makes it an ADT. For the sake of argument consider > > subtype Integer_X is Integer; > > Both are ADTs. > > BTW, a renaming would be the thing you are talking about. But Ada does not > have type renaming. People [mis]using subtypes for the purpose of renaming > must be prepared to nasty surprises. > >> There are some differences in *dynamic* behavior, but that has nothing to >> do >> with the available values and operations. (The text you quoted from the >> RM >> about values "belonging" to a subtype is defining dynamic behavior.) I >> recall some Dmitry guy telling us that dynamic behavior is different from >> static behavior, and even claiming that dynamic behavior cannot >> constitute a >> contract. So it if is not a *contract*, how come it matters for a *type* >> (which is an integral part of describing a contract)? > > I don't understand the point you are making. You cannot derive contract > from behavior, simply because it is converse: contract is imposed to > restrain possible behaviors. > > You might claim that implied contracts of Integer and Positive are exactly > same. I doubt that many would agree with that. I certainly wouldn't, because *I* consider the dynamic behavior to be part of the contract. But, clearly, you don't (and you've indicated that above again. So yes, given your world view, the contracts of Integer and Positive are exactly the same. That's clear, because they're interchangable in terms of legality and resolution (anything having to do with compile-time checking). The quote above says that you disagree with yourself. :-) "I doubt that many would agree with that." That's certainly true, but that's because few would agree with you on the notion that the contract does not include the dynamic behavior. In any case, either *you* have to agree with this premise (and thus all of your arguments on type vs. subtypes are nonsense), or you are no longer agreeing with your previous statements about contracts (which I for one would welcome, but it's seems pretty unlikely of a change). I'm sure you'll try to reconcile this by completely ignoring the rules of Ada and redefining all of the terms involved. Enjoy. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-15 21:17 ` Randy Brukardt @ 2013-03-16 7:51 ` Dmitry A. Kazakov 2013-03-16 9:30 ` Georg Bauhaus 2013-03-18 22:36 ` Randy Brukardt 0 siblings, 2 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-16 7:51 UTC (permalink / raw) On Fri, 15 Mar 2013 16:17:11 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:ewe0v3ck1xdo$.e8rtuof27ke6$.dlg@40tude.net... >> On Thu, 14 Mar 2013 17:12:28 -0500, Randy Brukardt wrote: >> >>> There are some differences in *dynamic* behavior, but that has nothing to do >>> with the available values and operations. (The text you quoted from the RM >>> about values "belonging" to a subtype is defining dynamic behavior.) I >>> recall some Dmitry guy telling us that dynamic behavior is different from >>> static behavior, and even claiming that dynamic behavior cannot constitute a >>> contract. So it if is not a *contract*, how come it matters for a *type* >>> (which is an integral part of describing a contract)? >> >> I don't understand the point you are making. You cannot derive contract >> from behavior, simply because it is converse: contract is imposed to >> restrain possible behaviors. >> >> You might claim that implied contracts of Integer and Positive are exactly >> same. I doubt that many would agree with that. > > I certainly wouldn't, because *I* consider the dynamic behavior to be part > of the contract. But, clearly, you don't (and you've indicated that above > again. So yes, given your world view, the contracts of Integer and Positive > are exactly the same. That's clear, because they're interchangable in terms > of legality and resolution (anything having to do with compile-time > checking). The quote above says that you disagree with yourself. :-) That would be a consequence of considering them same type. I already said, that this a path towards weak typing. But I don't see where I disagree with myself. Contract /= type. You can have same contract and different types. What about: type Same is new Integer; You also can have different contracts put on the same type in different contexts. You can have contracts on something that does not involve types at all. Anyway, I fail to see how contracts are relevant here. > "I doubt that many would agree with that." That's certainly true, but that's > because few would agree with you on the notion that the contract does not > include the dynamic behavior. In any case, either *you* have to agree with > this premise (and thus all of your arguments on type vs. subtypes are > nonsense), or you are no longer agreeing with your previous statements about > contracts (which I for one would welcome, but it's seems pretty unlikely of > a change). I don't see why. How *any* contract could make something like Positive a non-type? There is not many possibilities: A. Positive is not a type. This is what Georg says. I have no idea what this is supposed to mean. That 123 is not Positive, or that "+" is not applied to positives? He escapes into some kind of vague philosophy each time I ask. B. Positive is a type. The type is Integer. So Positive = Integer. This is evidently wrong because there exist programs which semantics sufficiently change when 'Integer' is replaced by 'Positive'. If the language treats them same, worse to the language. Luckily Ada checks if Positive is indeed positive (well, not always, but almost). C. not (A or B) = my point. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-16 7:51 ` Dmitry A. Kazakov @ 2013-03-16 9:30 ` Georg Bauhaus 2013-03-16 10:27 ` Dmitry A. Kazakov 2013-03-18 22:36 ` Randy Brukardt 1 sibling, 1 reply; 242+ messages in thread From: Georg Bauhaus @ 2013-03-16 9:30 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote: > On Fri, 15 Mar 2013 16:17:11 -0500, Randy Brukardt wrote: >> "I doubt that many would agree with that." That's certainly true, but that's >> because few would agree with you on the notion that the contract does not >> include the dynamic behavior. In any case, either *you* have to agree with >> this premise (and thus all of your arguments on type vs. subtypes are >> nonsense), or you are no longer agreeing with your previous statements about >> contracts (which I for one would welcome, but it's seems pretty unlikely of >> a change). > > I don't see why. How *any* contract could make something like Positive a > non-type? Sounds like begging the question, to me. And "contract" adds another source of lexical ambiguities. > A. Positive is not a type. This is what Georg says. I have no idea what > this is supposed to mean. It means what the RM says it means. The RM also says that 'Succ is invariant. *If* someone expects 'Succ to be what it is not, then the RM says why. The KOVOA theory does not, cannot, resolve the issue, else we would have seen a new draft of section 3? Subtype constraints are "weak" because in some contexts that seemed what was needed. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-16 9:30 ` Georg Bauhaus @ 2013-03-16 10:27 ` Dmitry A. Kazakov 2013-03-16 11:37 ` Georg Bauhaus 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-16 10:27 UTC (permalink / raw) On 16 Mar 2013 09:30:29 GMT, Georg Bauhaus wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote: >> On Fri, 15 Mar 2013 16:17:11 -0500, Randy Brukardt wrote: > >>> "I doubt that many would agree with that." That's certainly true, but that's >>> because few would agree with you on the notion that the contract does not >>> include the dynamic behavior. In any case, either *you* have to agree with >>> this premise (and thus all of your arguments on type vs. subtypes are >>> nonsense), or you are no longer agreeing with your previous statements about >>> contracts (which I for one would welcome, but it's seems pretty unlikely of >>> a change). >> >> I don't see why. How *any* contract could make something like Positive a >> non-type? > > Sounds like begging the question, to me. > > And "contract" adds another source of lexical ambiguities. Source of lexical ambiguities? This sounds like an encoding problem. Something wrong with your file system? >> A. Positive is not a type. This is what Georg says. I have no idea what >> this is supposed to mean. > > It means what the RM says it means. Which is? > Subtype constraints are "weak" because in some contexts > that seemed what was needed. You read that from the RM? -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-16 10:27 ` Dmitry A. Kazakov @ 2013-03-16 11:37 ` Georg Bauhaus 2013-03-16 13:04 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Georg Bauhaus @ 2013-03-16 11:37 UTC (permalink / raw) On 16.03.13 11:27, Dmitry A. Kazakov wrote: >> And "contract" adds another source of lexical ambiguities. > > Source of lexical ambiguities? This sounds like an encoding problem. It is a problem of semantics. Discussions ignited by a lack of definitions that will unambiguously assign meaning to "contract". >>> A. Positive is not a type. This is what Georg says. I have no idea what >>> this is supposed to mean. >> >> It means what the RM says it means. > > Which is? Randy said, in <khqpfb$b21$1@munin.nbi.dk>: "the quote you [Dmitry] made from the RM says as much." Positive is a KOVOA-type; Positive is a type-together-with in the Ada 83 Rationale; the type of Positive is not Positive by the LRM. "Is-a" and "is-not" are thus a contradiction if and only if one mixes contexts. There are three contexts above. We have to decide which context applies to 'Succ in an Ada program governed by the LRM. For problems of using the language, I choose the language's RM. I trust there is interest in a KOVOA draft of section 3, proposed to Ada-Comment. >> Subtype constraints are "weak" because in some contexts >> that seemed what was needed. > > You read that from the RM? I read what the inventor of the subtype, Ivan Godard, has had to say. http://newsgroups.derkeiler.com/Archive/Comp/comp.arch/2012-08/msg00360.html ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-16 11:37 ` Georg Bauhaus @ 2013-03-16 13:04 ` Dmitry A. Kazakov 2013-03-16 16:10 ` Georg Bauhaus 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-16 13:04 UTC (permalink / raw) On Sat, 16 Mar 2013 12:37:33 +0100, Georg Bauhaus wrote: > On 16.03.13 11:27, Dmitry A. Kazakov wrote: > >>> And "contract" adds another source of lexical ambiguities. >> >> Source of lexical ambiguities? This sounds like an encoding problem. > > It is a problem of semantics. A problem of semantics is lexical ambiguity...? >>>> A. Positive is not a type. This is what Georg says. I have no idea what >>>> this is supposed to mean. >>> >>> It means what the RM says it means. >> >> Which is? [...] Why don't you simply explain why in your opinion Positive is not a type? Without lexical ambiguities, semantic problems and other smoke and mirrors stuff. >>> Subtype constraints are "weak" because in some contexts >>> that seemed what was needed. >> >> You read that from the RM? > > I read what the inventor of the subtype, Ivan Godard, has had to say. > http://newsgroups.derkeiler.com/Archive/Comp/comp.arch/2012-08/msg00360.html To paraphrase Omar: if those books are in agreement with the RM, we have no need of them; and if these are opposed to the RM, destroy them. (:-)) -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-16 13:04 ` Dmitry A. Kazakov @ 2013-03-16 16:10 ` Georg Bauhaus 2013-03-16 17:47 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Georg Bauhaus @ 2013-03-16 16:10 UTC (permalink / raw) On 16.03.13 14:04, Dmitry A. Kazakov wrote: > On Sat, 16 Mar 2013 12:37:33 +0100, Georg Bauhaus wrote: > >> On 16.03.13 11:27, Dmitry A. Kazakov wrote: >> >>>> And "contract" adds another source of lexical ambiguities. >>> >>> Source of lexical ambiguities? This sounds like an encoding problem. >> >> It is a problem of semantics. > > A problem of semantics is lexical ambiguity...? Lexical ambiguity as in "This word can be understood in two or more different ways". The word "contract" is of this kind, which is one cause of heated debate. > Why don't you simply explain why in your opinion Positive is not a type? Whether or not Positive'Succ *is* invariant depends solely on definitions of Ada, not on my opinion. Whether or not 'Succ *should* become something else in order for a certain kind of types-with-predicates to work has been, and is an interesting question. It is not satisfactorily answered, though, by saying the what *is* is not what it is but claiming that it is what it *should* be (algebraic "sub-types", inheritance, whatever). It isn't (both senses). > To paraphrase Omar: if those books are in agreement with the RM, we have no > need of them; and if these are opposed to the RM, destroy them. (:-)) I only asked that words should be marked as referring to Ada or to something else. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-16 16:10 ` Georg Bauhaus @ 2013-03-16 17:47 ` Dmitry A. Kazakov 0 siblings, 0 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-16 17:47 UTC (permalink / raw) On Sat, 16 Mar 2013 17:10:17 +0100, Georg Bauhaus wrote: > On 16.03.13 14:04, Dmitry A. Kazakov wrote: >> Why don't you simply explain why in your opinion Positive is not a type? > > Whether or not Positive'Succ *is* invariant depends solely on definitions > of Ada, not on my opinion. You don't answer the question. How Ada defines S'Succ is pretty clear. In question is why so and could it be different. I already listed all variants. There are 4 of them + 1 when the operation gets disallowed. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-16 7:51 ` Dmitry A. Kazakov 2013-03-16 9:30 ` Georg Bauhaus @ 2013-03-18 22:36 ` Randy Brukardt 2013-03-19 10:14 ` Dmitry A. Kazakov 1 sibling, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-03-18 22:36 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:hiybjkhz3p5d.1x6dxfr1ptgcg.dlg@40tude.net... > On Fri, 15 Mar 2013 16:17:11 -0500, Randy Brukardt wrote: > >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >> news:ewe0v3ck1xdo$.e8rtuof27ke6$.dlg@40tude.net... >>> On Thu, 14 Mar 2013 17:12:28 -0500, Randy Brukardt wrote: >>> >>>> There are some differences in *dynamic* behavior, but that has nothing >>>> to do >>>> with the available values and operations. (The text you quoted from the >>>> RM >>>> about values "belonging" to a subtype is defining dynamic behavior.) I >>>> recall some Dmitry guy telling us that dynamic behavior is different >>>> from >>>> static behavior, and even claiming that dynamic behavior cannot >>>> constitute a >>>> contract. So it if is not a *contract*, how come it matters for a >>>> *type* >>>> (which is an integral part of describing a contract)? >>> >>> I don't understand the point you are making. You cannot derive contract >>> from behavior, simply because it is converse: contract is imposed to >>> restrain possible behaviors. >>> >>> You might claim that implied contracts of Integer and Positive are >>> exactly >>> same. I doubt that many would agree with that. >> >> I certainly wouldn't, because *I* consider the dynamic behavior to be >> part >> of the contract. But, clearly, you don't (and you've indicated that above >> again. So yes, given your world view, the contracts of Integer and >> Positive >> are exactly the same. That's clear, because they're interchangable in >> terms >> of legality and resolution (anything having to do with compile-time >> checking). The quote above says that you disagree with yourself. :-) > > That would be a consequence of considering them same type. I already said, > that this a path towards weak typing. > > But I don't see where I disagree with myself. Contract /= type. You can > have same contract and different types. What about: > > type Same is new Integer; This definitely has a different contract, as it is not compatible with Integer's contract. Yes, it has the same set of values and operations with the same name, profile, and bodies, but it's still a different contract because the types involved are an intergral part of the contract. > You also can have different contracts put on the same type in different > contexts. You can have contracts on something that does not involve types > at all. Anyway, I fail to see how contracts are relevant here. Because types are an important part of a contract (that is, in Ada terms, the profile). Two operations with different profiles are different, even if everything else is the same (the implementation, names of things, etc.) ... > I don't see why. How *any* contract could make something like Positive a > non-type? There is not many possibilities: > > A. Positive is not a type. This is what Georg says. I have no idea what > this is supposed to mean. That 123 is not Positive, or that "+" is not > applied to positives? He escapes into some kind of vague philosophy each > time I ask. I agree with Georg; Positive is not a type; it *has* a type. Neither is Integer a type; it *has* a type. (All types in Ada are anonymous.) As such, the "+" that applied to Positive is the same one that's applied to Integer. That's *not* the case for a type like the one associated with Same, as you declared it above. > B. Positive is a type. The type is Integer. So Positive = Integer. This is > evidently wrong because there exist programs which semantics sufficiently > change when 'Integer' is replaced by 'Positive'. If the language treats > them same, worse to the language. Luckily Ada checks if Positive is indeed > positive (well, not always, but almost). This is also true, except for the first sentence. But you're confusing the issue by talking about "semantics". Types are only about static semantics (that is, compile-time behavior). Run-time semantics aren't involved. It's the same as for profiles, operations, and the like. In this sense, a type is part of your model for contracts, where there is no run-time component. Run-time semantics get added on top of that, but that has no effect on the legality of a program, so it is completely orthogonal to the type/profile. > C. not (A or B) = my point. Actually, both A and B are true, claiming their exclusive doesn't make any sense. Or maybe it's better to call them irrelevant, as the relationship "is" doesn't apply to "Positive" and "type" in Ada (or any named entity, for that matter). It would be like saying: A. Dump truck is not an engine. B. Dump truck is an engine. C. not (A or B). C is the only statement that makes sense here, as a dump truck "has" an engine, but it surely is not an engine. (It has many other parts as well, and the same is true for Positive.) Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-18 22:36 ` Randy Brukardt @ 2013-03-19 10:14 ` Dmitry A. Kazakov 2013-03-19 14:23 ` Georg Bauhaus 2013-03-19 21:37 ` Randy Brukardt 0 siblings, 2 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-19 10:14 UTC (permalink / raw) On Mon, 18 Mar 2013 17:36:31 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:hiybjkhz3p5d.1x6dxfr1ptgcg.dlg@40tude.net... >> But I don't see where I disagree with myself. Contract /= type. You can >> have same contract and different types. What about: >> >> type Same is new Integer; > > This definitely has a different contract, as it is not compatible with > Integer's contract. Yes, it has the same set of values and operations with > the same name, profile, and bodies, but it's still a different contract > because the types involved are an intergral part of the contract. See, you just defined a contract in terms of types while using contracts to define type as same/different/non-existent. You cannot have it in both ways. >> You also can have different contracts put on the same type in different >> contexts. You can have contracts on something that does not involve types >> at all. Anyway, I fail to see how contracts are relevant here. > > Because types are an important part of a contract (that is, in Ada terms, > the profile). *if* you want to contract a type, *then* that cannot be a part of. In any case, contract is much less a language term than type. It is more about design and the problem space. It may apply to a type when the type is used to represent some domain entity but it cannot define what types are. A type is values+operations. > Two operations with different profiles are different, even if > everything else is the same (the implementation, names of things, etc.) Ada has *nominal* equivalence of operations. Two operations are different just because they are declared in different places. It is not because of their profiles. On top of that there are rules about overloading/overriding where profiles get involved, but that is not like C where you can repeat declarations. >> I don't see why. How *any* contract could make something like Positive a >> non-type? There is not many possibilities: >> >> A. Positive is not a type. This is what Georg says. I have no idea what >> this is supposed to mean. That 123 is not Positive, or that "+" is not >> applied to positives? He escapes into some kind of vague philosophy each >> time I ask. > > I agree with Georg; Positive is not a type; it *has* a type. Neither is > Integer a type; it *has* a type. Since there is an equivalence between Positive and the type is "has," Positive as a name unambiguously refers to that type, i.e. "Positive" is the name of the type. Unless you have other legal name for it. But you don't in Ada. You have absolutely no language means whatsoever to distinguish Positive and the type of. So, what merits has this distinction if it cannot be observed? > (All types in Ada are anonymous.) Great, then let them be, where there belong to, in the celestial spheres, and let us call type something that indeed exists in the language and has a name. > Types are only about static semantics > (that is, compile-time behavior). Run-time semantics aren't involved. Run-time semantics is what makes program working or not working. Types are all about run-time semantics nothing else counts. Type checks is a way to prove something about [run-time] semantics at compile time. Types neither ensure nor required for a program to behave correctly. They are a tool to ease reaching that goal. > Run-time semantics get added on top of that, but that has no effect on the > legality of a program, so it is completely orthogonal to the type/profile. Legality is irrelevant as we consider only legal Ada programs. There exist legal Ada programs which change their run-time behavior when 'Positive' is replaced by 'Integer' and reverse. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-19 10:14 ` Dmitry A. Kazakov @ 2013-03-19 14:23 ` Georg Bauhaus 2013-03-19 15:13 ` Dmitry A. Kazakov 2013-03-19 21:37 ` Randy Brukardt 1 sibling, 1 reply; 242+ messages in thread From: Georg Bauhaus @ 2013-03-19 14:23 UTC (permalink / raw) On 19.03.13 11:14, Dmitry A. Kazakov wrote: > "Positive" is the name of the type. How can something have a name if it is known to be anonymous? ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-19 14:23 ` Georg Bauhaus @ 2013-03-19 15:13 ` Dmitry A. Kazakov 2013-03-19 16:52 ` Georg Bauhaus 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-19 15:13 UTC (permalink / raw) On Tue, 19 Mar 2013 15:23:15 +0100, Georg Bauhaus wrote: > On 19.03.13 11:14, Dmitry A. Kazakov wrote: >> "Positive" is the name of the type. > > How can something have a name if it is known to be anonymous? http://en.wikipedia.org/wiki/Name The first two sentences. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-19 15:13 ` Dmitry A. Kazakov @ 2013-03-19 16:52 ` Georg Bauhaus 2013-03-19 17:31 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Georg Bauhaus @ 2013-03-19 16:52 UTC (permalink / raw) On 19.03.13 16:13, Dmitry A. Kazakov wrote: > On Tue, 19 Mar 2013 15:23:15 +0100, Georg Bauhaus wrote: > >> On 19.03.13 11:14, Dmitry A. Kazakov wrote: >>> "Positive" is the name of the type. >> >> How can something have a name if it is known to be anonymous? > > http://en.wikipedia.org/wiki/Name > > The first two sentences. These names apply to things that are eligible for naming. An Ada type, by definition, is not eligible for naming (like you have said). That's the rule of law. It was a joke, anyway. I'm still waiting for the set of formalized definitions that rewrite LRM 3, since they need to put down words that redefine "type" and "subtype" from the ground up (even when that's "just ..."). Until then, everything conflates matters, I think. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-19 16:52 ` Georg Bauhaus @ 2013-03-19 17:31 ` Dmitry A. Kazakov 2013-03-19 20:07 ` J-P. Rosen 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-19 17:31 UTC (permalink / raw) On Tue, 19 Mar 2013 17:52:13 +0100, Georg Bauhaus wrote: > I'm still waiting for the set of > formalized definitions that rewrite LRM 3, since they need > to put down words that redefine "type" and "subtype" from > the ground up (even when that's "just ..."). Positive is the name of an abstract data type with values from 1 to Integer'Last and operations inherited from the type, which name is Integer. Type is a tuple: set of values x set of operations [with at least an argument or result of the type]. Subtype is a type that inherits some operations (interface) of another type, called "parent type," "base type," "ancestor type" or "supertype." Subtyping relation is transitive and reflexive. Class is the transitive closure of. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-19 17:31 ` Dmitry A. Kazakov @ 2013-03-19 20:07 ` J-P. Rosen 2013-03-19 20:45 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: J-P. Rosen @ 2013-03-19 20:07 UTC (permalink / raw) Le 19/03/2013 18:31, Dmitry A. Kazakov a �crit : > Subtype is a type that inherits some operations (interface) of another > type, called "parent type," "base type," "ancestor type" or "supertype." This may be the source of the confusion. What you describe is called "subtype" in other languages, but this is called "derived type" in Ada. An Ada subtype is a completely different beast, that does not correspond to this definition. And please, bear in mind that other languages do not have anything similar to Ada subtypes, therefore you cannot compare Ada subtypes to features of other languages. -- J-P. Rosen Adalog 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00 http://www.adalog.fr ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-19 20:07 ` J-P. Rosen @ 2013-03-19 20:45 ` Dmitry A. Kazakov 2013-03-19 21:59 ` J-P. Rosen 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-19 20:45 UTC (permalink / raw) On Tue, 19 Mar 2013 21:07:18 +0100, J-P. Rosen wrote: > Le 19/03/2013 18:31, Dmitry A. Kazakov a �crit : >> Subtype is a type that inherits some operations (interface) of another >> type, called "parent type," "base type," "ancestor type" or "supertype." > > This may be the source of the confusion. What you describe is called > "subtype" in other languages, but this is called "derived type" in Ada. > An Ada subtype is a completely different beast, that does not correspond > to this definition. And how is it different? > And please, bear in mind that other languages do not have anything > similar to Ada subtypes, therefore you cannot compare Ada subtypes to > features of other languages. Practically all languages have subtypes which share the representation of the parent while adding a constraint. E.g. const T in C++ is such a subtype. Of course insistence on keeping the representation erodes the principle of separation interface and implementation. Ada would be much better off if all derived types could change the representation like arrays do when constrained. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-19 20:45 ` Dmitry A. Kazakov @ 2013-03-19 21:59 ` J-P. Rosen 2013-03-20 10:04 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: J-P. Rosen @ 2013-03-19 21:59 UTC (permalink / raw) Le 19/03/2013 21:45, Dmitry A. Kazakov a �crit : >>> Subtype is a type that inherits some operations (interface) of another >>> >> type, called "parent type," "base type," "ancestor type" or "supertype." >> > >> > This may be the source of the confusion. What you describe is called >> > "subtype" in other languages, but this is called "derived type" in Ada. >> > An Ada subtype is a completely different beast, that does not correspond >> > to this definition. > And how is it different? > It is different in that a subtype does NOT inherit operations, it has the SAME operations as its type. Proof: a fundamental feature of OOP is that you can redefine inherited operations. You cannot redefine operations of a subtype to be different from those of its type. Note also that a subtype is a property of an object; a value has no subtype, only a type. Therefore, it would not be possible to dispatch according to the subtype, since you would not know which operation to use if the controlling operand is a plain value. Now, you can argue that these are all more flaws of Ada - or recognize at last that a subtype is not a different type. -- J-P. Rosen Adalog 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00 http://www.adalog.fr ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-19 21:59 ` J-P. Rosen @ 2013-03-20 10:04 ` Dmitry A. Kazakov 2013-03-20 11:01 ` J-P. Rosen 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-20 10:04 UTC (permalink / raw) On Tue, 19 Mar 2013 22:59:22 +0100, J-P. Rosen wrote: > Le 19/03/2013 21:45, Dmitry A. Kazakov a �crit : >>>> Subtype is a type that inherits some operations (interface) of another >>>> >> type, called "parent type," "base type," "ancestor type" or "supertype." >>> > >>> > This may be the source of the confusion. What you describe is called >>> > "subtype" in other languages, but this is called "derived type" in Ada. >>> > An Ada subtype is a completely different beast, that does not correspond >>> > to this definition. >> And how is it different? >> > It is different in that a subtype does NOT inherit operations, it has > the SAME operations as its type. How do you know that they are same? In what sense are they same? But they are evidently not same: procedure Foo (X : out Integer) is begin X := -1; end Foo; when inherited by Positive changes its behavior. > Proof: a fundamental feature of OOP is that you can redefine inherited > operations. You cannot redefine operations of a subtype to be different > from those of its type. But they are redefined. The compiler adds conversion to the subtype for each in-argument and conversion from the subtype for each out-argument. Which is what happens with Foo above the body of procedure Foo (X : out Positive) is the body of procedure Foo (X : out Integer) + constraint check. > Note also that a subtype is a property of an object; a value has no > subtype, only a type. No, subtyping is a relation between two types, denoted as T<:S. Object has no subtype, it has a type. So does a value. >Therefore, it would not be possible to dispatch > according to the subtype, since you would not know which operation to > use if the controlling operand is a plain value. It is impossible to dispatch on a specific type anyway. Dispatching happens only on a class-wide type. Integer and Positive indeed form a class, but Ada, presently, has no type corresponding to that class, e.g. Integer'Class. If it had, and if you had an object of the type Integer'Class, then you could dispatch. Which is BTW, a highly desired improvement which would for example sort out the mess we have with string types. > Now, you can argue that these are all more flaws of Ada - or recognize > at last that a subtype is not a different type. Not at all. Ada 83 subtypes are consistent with the type model when they are considered abstract data types, as they surely are. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-20 10:04 ` Dmitry A. Kazakov @ 2013-03-20 11:01 ` J-P. Rosen 2013-03-20 13:21 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: J-P. Rosen @ 2013-03-20 11:01 UTC (permalink / raw) Le 20/03/2013 11:04, Dmitry A. Kazakov a �crit : >> It is different in that a subtype does NOT inherit operations, it has >> the SAME operations as its type. > > How do you know that they are same? In what sense are they same? > > But they are evidently not same: > > procedure Foo (X : out Integer) is > begin > X := -1; > end Foo; > > when inherited by Positive changes its behavior. They are not inherited! You can call the above Foo with a variable of type Positive; Constraint_Error is raised after the call when converting back. But once again, it is the same operation that is called by Integer and Positive. >> Proof: a fundamental feature of OOP is that you can redefine inherited >> operations. You cannot redefine operations of a subtype to be different >> from those of its type. > > But they are redefined. The compiler adds conversion to the subtype for > each in-argument and conversion from the subtype for each out-argument. > Which is what happens with Foo above the body of > > procedure Foo (X : out Positive) > > is the body of > > procedure Foo (X : out Integer) + constraint check. > This is not the way it is defined in Ada, and what I said is that the user cannot redefine Foo for Positive. >> Note also that a subtype is a property of an object; a value has no >> subtype, only a type. > > No, subtyping is a relation between two types, denoted as T<:S. In standard OO speak yes, but that is NOT the meaning in Ada. > Object has no subtype, it has a type. So does a value. An object has a subtype that defines a constraint to be checked when assigning to it. You may view or describe features of Ada any way you please (I do sometimes cheat with the official model for explanatory purposes when I'm teaching), but here we are discussing the official model of Ada, and what words mean as defined in ISO-8652:2012. The term "subtype" as defined there is not what you use it for. -- J-P. Rosen Adalog 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00 http://www.adalog.fr ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-20 11:01 ` J-P. Rosen @ 2013-03-20 13:21 ` Dmitry A. Kazakov 2013-03-20 23:31 ` Randy Brukardt 2013-03-22 10:23 ` J-P. Rosen 0 siblings, 2 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-20 13:21 UTC (permalink / raw) On Wed, 20 Mar 2013 12:01:25 +0100, J-P. Rosen wrote: > Le 20/03/2013 11:04, Dmitry A. Kazakov a �crit : >>> It is different in that a subtype does NOT inherit operations, it has >>> the SAME operations as its type. >> >> How do you know that they are same? In what sense are they same? >> >> But they are evidently not same: >> >> procedure Foo (X : out Integer) is >> begin >> X := -1; >> end Foo; >> >> when inherited by Positive changes its behavior. > They are not inherited! You can call the above Foo with a variable of > type Positive; Constraint_Error is raised after the call when converting > back. But once again, it is the same operation that is called by Integer > and Positive. See, same operation applied to same value of same type gives different result. This is called UNTYPED. >>> Proof: a fundamental feature of OOP is that you can redefine inherited >>> operations. You cannot redefine operations of a subtype to be different >>> from those of its type. >> >> But they are redefined. The compiler adds conversion to the subtype for >> each in-argument and conversion from the subtype for each out-argument. >> Which is what happens with Foo above the body of >> >> procedure Foo (X : out Positive) >> >> is the body of >> >> procedure Foo (X : out Integer) + constraint check. >> > This is not the way it is defined in Ada, This is the way it works, so it is the way it is. > and what I said is that the > user cannot redefine Foo for Positive. Which was the core problem with the subtype Prime and the operation 'Succ the OP reported. Inheritance as-is composed with a conversion is relatively harmless when the constraint is a range. But when the constraint is arbitrary it would break almost everything and it does. This is a hard mathematical fact, no LRM or ISO has any authority here. >>> Note also that a subtype is a property of an object; a value has no >>> subtype, only a type. >> >> No, subtyping is a relation between two types, denoted as T<:S. > In standard OO speak yes, but that is NOT the meaning in Ada. The definition is independent on any language. I don't redefine the meaning of Ada-subtype. I translate Ada's definition into the terms of ADT. In these terms Ada-subtype is a proper type. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-20 13:21 ` Dmitry A. Kazakov @ 2013-03-20 23:31 ` Randy Brukardt 2013-03-21 9:08 ` Dmitry A. Kazakov 2013-03-22 10:23 ` J-P. Rosen 1 sibling, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-03-20 23:31 UTC (permalink / raw) [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #1: Type: text/plain, Size: 3228 bytes --] "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:1xg9wka6slgit.1q0leacagdeuv.dlg@40tude.net... > On Wed, 20 Mar 2013 12:01:25 +0100, J-P. Rosen wrote: > >> Le 20/03/2013 11:04, Dmitry A. Kazakov a �crit : >>>> It is different in that a subtype does NOT inherit operations, it has >>>> the SAME operations as its type. >>> >>> How do you know that they are same? In what sense are they same? >>> >>> But they are evidently not same: >>> >>> procedure Foo (X : out Integer) is >>> begin >>> X := -1; >>> end Foo; >>> >>> when inherited by Positive changes its behavior. > >> They are not inherited! You can call the above Foo with a variable of >> type Positive; Constraint_Error is raised after the call when converting >> back. But once again, it is the same operation that is called by Integer >> and Positive. > > See, same operation applied to same value of same type gives different > result. > > This is called UNTYPED. Sounds right to me; by the rules of your useless definitions, you can clearly prove that Ada is untyped. Since Integer and Positive are names for the same type, with non-type properties involved. Calling this "untyped" makes much more sense than trying to claim some sort of inheritance relationship (which is almost always the case, inheritance is almost never worth the mental energy expended upon it). To me, this just demostrates the worthlessness of your definitions when applied to Ada. Apparently others feel the same way. ... > Inheritance as-is composed with a conversion is relatively harmless when > the constraint is a range. But when the constraint is arbitrary it would > break almost everything and it does. This is a hard mathematical fact, no > LRM or ISO has any authority here. The whole idea of "inheritance" has almost no value in any context. It's definitely not worth the energy that people (including) have put into it. A model where every type started with a clean slate other than predefined operations works just as well. ... > The definition is independent on any language. I don't redefine the > meaning > of Ada-subtype. I translate Ada's definition into the terms of ADT. In > these terms Ada-subtype is a proper type. I disagree that Integer is an "ADT" in the first place. There is nothing "abstract" about Integer or any numeric type (even using the English meaning of "abstract") -- all of the values and operations are known and defined by the type declaration. Calling it an "ADT" seems brain-damaged to me; an ADT in Ada is a private type or an interface or an abstract type -- there has to be something hidden. In any case, this discussion has run its course. So long as you cling to a useless and different terminlogy, we really can't discuss the interesting topics, like the value of Integer'Class. This is a useful idea, but not the way you describe it. If you claim that it has something useful to do with subtypes, you are already so far off the rails that there is nothing to talk about. We're not going to jettison 40 years of Ada education and understanding just to adopt a model that makes Dmitry more comfortable! So I'm done here. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-20 23:31 ` Randy Brukardt @ 2013-03-21 9:08 ` Dmitry A. Kazakov 0 siblings, 0 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-21 9:08 UTC (permalink / raw) On Wed, 20 Mar 2013 18:31:29 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:1xg9wka6slgit.1q0leacagdeuv.dlg@40tude.net... >> On Wed, 20 Mar 2013 12:01:25 +0100, J-P. Rosen wrote: >> >>> Le 20/03/2013 11:04, Dmitry A. Kazakov a 嚙踝蕭it : >>>>> It is different in that a subtype does NOT inherit operations, it has >>>>> the SAME operations as its type. >>>> >>>> How do you know that they are same? In what sense are they same? >>>> >>>> But they are evidently not same: >>>> >>>> procedure Foo (X : out Integer) is >>>> begin >>>> X := -1; >>>> end Foo; >>>> >>>> when inherited by Positive changes its behavior. >> >>> They are not inherited! You can call the above Foo with a variable of >>> type Positive; Constraint_Error is raised after the call when converting >>> back. But once again, it is the same operation that is called by Integer >>> and Positive. >> >> See, same operation applied to same value of same type gives different >> result. >> >> This is called UNTYPED. > > Sounds right to me; by the rules of your useless definitions, you can > clearly prove that Ada is untyped. Nope. A language is untyped only if no typed interpretation of its semantics exists. J-P gave an untyped interpretation of Ada's Positive. I proposed a typed one. Thus, Ada is typed. [...] > To me, this just demostrates the worthlessness of your definitions when > applied to Ada. Apparently others feel the same way. Sorry, that is not mine definitions, it is *your* worthy definition according to which *same* operation on *same* value of *same* type yields *different* results. >> Inheritance as-is composed with a conversion is relatively harmless when >> the constraint is a range. But when the constraint is arbitrary it would >> break almost everything and it does. This is a hard mathematical fact, no >> LRM or ISO has any authority here. > > The whole idea of "inheritance" has almost no value in any context. It's > definitely not worth the energy that people (including) have put into it. A > model where every type started with a clean slate other than predefined > operations works just as well. Once you create an Ada subtype you inherit operations of the base. If you don't like it, you should be the first for allowing at least overriding inherited operations, when they become junk as in the case of Prime'Succ. You should also be in favor for means to specify what should be inherited. The only mechanism for this I know is explicit interfaces. >> The definition is independent on any language. I don't redefine the meaning >> of Ada-subtype. I translate Ada's definition into the terms of ADT. In >> these terms Ada-subtype is a proper type. > > I disagree that Integer is an "ADT" in the first place. There is nothing > "abstract" about Integer or any numeric type (even using the English meaning > of "abstract") -- all of the values and operations are known and defined by > the type declaration. Calling it an "ADT" seems brain-damaged to me; an ADT > in Ada is a private type or an interface or an abstract type -- there has to > be something hidden. Abstract in ADT means that the specification is abstracted from the implementation. Anyway, is it only abstractness you are against? From your posts I have an impression that Integer is not only non-"abstract," but also not a "type," and possibly not even "data." -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-20 13:21 ` Dmitry A. Kazakov 2013-03-20 23:31 ` Randy Brukardt @ 2013-03-22 10:23 ` J-P. Rosen 2013-03-22 14:54 ` Dmitry A. Kazakov 1 sibling, 1 reply; 242+ messages in thread From: J-P. Rosen @ 2013-03-22 10:23 UTC (permalink / raw) Le 20/03/2013 14:21, Dmitry A. Kazakov a �crit : > See, same operation applied to same value of same type gives different > result. > > This is called UNTYPED. No, it is not the operation that gives different result, it's the assignment of a value that is incompatible with the variable's constraint that raises C_E. >>> No, subtyping is a relation between two types, denoted as T<:S. >> In standard OO speak yes, but that is NOT the meaning in Ada. > > The definition is independent on any language. I don't redefine the meaning > of Ada-subtype. I translate Ada's definition into the terms of ADT. In > these terms Ada-subtype is a proper type. > The theory of ADT has no notion of subtypes (Ada definition). Therefore, you can't translate Ada's subtypes into the terms of ADT. You insist on subtypes being types in a desperate effort to map them to ADT, but sorry, it is not possible. They are different. -- J-P. Rosen Adalog 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00 http://www.adalog.fr ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-22 10:23 ` J-P. Rosen @ 2013-03-22 14:54 ` Dmitry A. Kazakov 2013-03-22 22:18 ` J-P. Rosen 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-22 14:54 UTC (permalink / raw) On Fri, 22 Mar 2013 11:23:09 +0100, J-P. Rosen wrote: > Le 20/03/2013 14:21, Dmitry A. Kazakov a �crit : > >> See, same operation applied to same value of same type gives different >> result. >> >> This is called UNTYPED. > No, it is not the operation that gives different result, it's the > assignment of a value that is incompatible with the variable's > constraint that raises C_E. There is no assignment in my example. Assignment is in the *body* of the operation Foo. The effect is different when Foo is called on a variable of Integer vs. Positive "non-types." Are you saying that one have to look into the bodies, on top of having it untyped? And what is so special about assignments? > The theory of ADT has no notion of subtypes (Ada definition). There is nothing special in Ada-subtypes. They are just ADTs. > Therefore, > you can't translate Ada's subtypes into the terms of ADT. I just did it. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-22 14:54 ` Dmitry A. Kazakov @ 2013-03-22 22:18 ` J-P. Rosen 2013-03-22 23:05 ` Shark8 2013-03-23 8:14 ` Dmitry A. Kazakov 0 siblings, 2 replies; 242+ messages in thread From: J-P. Rosen @ 2013-03-22 22:18 UTC (permalink / raw) Le 22/03/2013 15:54, Dmitry A. Kazakov a �crit : >> No, it is not the operation that gives different result, it's the >> > assignment of a value that is incompatible with the variable's >> > constraint that raises C_E. > There is no assignment in my example. Assignment is in the *body* of the > operation Foo. No, assignment happens after returning from Foo. [..] > And what is so special about assignments? Assignment is to a variable, and a variable has a subtype. It's the checking of the constraint when assigning to a variable that raises C_E. >> > The theory of ADT has no notion of subtypes (Ada definition). > There is nothing special in Ada-subtypes. They are just ADTs. You say they are. The rest of the world says they are not. We have come to the point where nothing else can be added. >> > Therefore, >> > you can't translate Ada's subtypes into the terms of ADT. > I just did it. And that's where everybody (including those who designed/maintain the language) thinks you are wrong. -- J-P. Rosen Adalog 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00 http://www.adalog.fr ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-22 22:18 ` J-P. Rosen @ 2013-03-22 23:05 ` Shark8 2013-03-23 8:32 ` Dmitry A. Kazakov 2013-03-23 8:14 ` Dmitry A. Kazakov 1 sibling, 1 reply; 242+ messages in thread From: Shark8 @ 2013-03-22 23:05 UTC (permalink / raw) On Friday, March 22, 2013 4:18:02 PM UTC-6, J-P. Rosen wrote: > Le 22/03/2013 15:54, Dmitry A. Kazakov a �crit : > > >> > Therefore, > >> > you can't translate Ada's subtypes into the terms of ADT. > > I just did it. > > And that's where everybody (including those who designed/maintain the > language) thinks you are wrong. I think I can see Dmitry's point but, like you said earlier, it's a matter of definitions if you'll allow me a stab at Dmitry->everybody-else translation it's like this: The notion of TYPE is two sets: {v | values of the type} & {o | operations on that type} Given that a "subtype" may have different valid values 'v' than its parent type (e.g. Positive has restricted valid-values than Integer) then he wishes to call it a TYPE. Everyone else is saying that Ada's notion of "subtype" contains a third set, a subset of of v {valid | the valid values}, and that v /= valid is not reason to panic and call "subtype" a true type simply because there are [possibly] values contained in its parent's v that are not present in the subtype's valid. So the problem is in the conflation of "values" and "valid values" of some [sub]type. ---------------------------------------------------------------- That all is, IMO, a problem exacerbated in CS by the overpowering prevalence of "extension" in the "Object Oriented" paradigm; this even to the point that some of the new CS graduates [superficially] seem utterly unable to grasp the usefulness/utility of excluding values. {Though the attitude is surprising given the math/logic background/history of CS: where one routinely excludes things as a premise.} -- It's so odd that the idea of subtyping is so rare that it becomes difficult to explain the usefulness thereof to other programmers {like trying to explain that a "plow" is a good/useful thing to [other] farmers...} simply because the idea is so _obvious_. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-22 23:05 ` Shark8 @ 2013-03-23 8:32 ` Dmitry A. Kazakov 0 siblings, 0 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-23 8:32 UTC (permalink / raw) On Fri, 22 Mar 2013 16:05:47 -0700 (PDT), Shark8 wrote: > On Friday, March 22, 2013 4:18:02 PM UTC-6, J-P. Rosen wrote: >> Le 22/03/2013 15:54, Dmitry A. Kazakov a �crit : >> >>>> > Therefore, >>>> > you can't translate Ada's subtypes into the terms of ADT. >>> I just did it. >> >> And that's where everybody (including those who designed/maintain the >> language) thinks you are wrong. > > I think I can see Dmitry's point but, like you said earlier, it's a matter > of definitions Then there should an alternative definition of ADT... > So the problem is in the conflation of "values" and "valid values" of some [sub]type. The problem is that subset is a set. So valid values are simply values of Positive. If you don't change the definition of ADT, Positive will keep on being ADT. > That all is, IMO, a problem exacerbated in CS by the overpowering > prevalence of "extension" in the "Object Oriented" paradigm; this even to > the point that some of the new CS graduates [superficially] seem utterly > unable to grasp the usefulness/utility of excluding values. Right. The litmus test is to ask somebody who does not know Ada, isn't C's int a class (type). This would produce no less fume as Positive vs. ADT. It is a pity that Ada community keeps on insisting on this on their side of the wall, refusing to see that either subtype or tagged type, they are just different ways of creating a new type from existing ones, while having a type for objects accommodating values of both ancestor and predecessor types. There is no reason why derived types shall always be extensions. It is an *implementation* detail. Ada people should knew better about separation of interface and implementation. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-22 22:18 ` J-P. Rosen 2013-03-22 23:05 ` Shark8 @ 2013-03-23 8:14 ` Dmitry A. Kazakov 2013-03-23 9:02 ` J-P. Rosen 1 sibling, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-23 8:14 UTC (permalink / raw) On Fri, 22 Mar 2013 23:18:02 +0100, J-P. Rosen wrote: > Le 22/03/2013 15:54, Dmitry A. Kazakov a �crit : >>> No, it is not the operation that gives different result, it's the >>> > assignment of a value that is incompatible with the variable's >>> > constraint that raises C_E. >> There is no assignment in my example. Assignment is in the *body* of the >> operation Foo. > No, assignment happens after returning from Foo. You mean "assignment operation," rather than "assignment statement"? Fine, that won't safe you either. Replace "the operation Foo of Positive," with "the assignment operation of Positive." You still have different behavior of an operation. I used Foo merely to prevent yet another fume about whether assignment is an operation. If it is, then simply consider: declare X : Positive; begin X := -1; -- With Integer it behaves *differently* end; So, WHERE is the difference, what make the program above to work differently, if everything [value, type, operation] is SAME? >>> > The theory of ADT has no notion of subtypes (Ada definition). >> There is nothing special in Ada-subtypes. They are just ADTs. > You say they are. The rest of the world says they are not. Georg and Randy seem to dismiss ADT altogether. > We have come > to the point where nothing else can be added. You could add, if you are not with Georg and Randy, why you think Positive is not an ADT. >>> > Therefore, >>> > you can't translate Ada's subtypes into the terms of ADT. >> I just did it. > And that's where everybody (including those who designed/maintain the > language) thinks you are wrong. But none said why. They should have indicated some flaws in the mapping Positive ~ ADT. So far the only argument was that ADT is useless. May be, but irrelevant, because it tells nothing about why Positive is not an ADT. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-23 8:14 ` Dmitry A. Kazakov @ 2013-03-23 9:02 ` J-P. Rosen 2013-03-23 10:19 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: J-P. Rosen @ 2013-03-23 9:02 UTC (permalink / raw) Le 23/03/2013 09:14, Dmitry A. Kazakov a �crit : > declare > X : Positive; > begin > X := -1; -- With Integer it behaves *differently* > end; > > So, WHERE is the difference, what make the program above to work > differently, if everything [value, type, operation] is SAME? The values are the same, the subtype is a property of a variable. The assignment behaves the same: check that the value belongs to the allowed values for the variable, and raise C_E if not. The check succeeds for some variables, and fails for others. This does not mean it is a different operation. Once again: a subtype is just an extra check added in some contexts to some objects. It does not define a new set of values, i.e. the "1" for Positive is the same as the "1" for Integer (while it is different from the "1" of some user defined type). -- J-P. Rosen Adalog 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00 http://www.adalog.fr ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-23 9:02 ` J-P. Rosen @ 2013-03-23 10:19 ` Dmitry A. Kazakov 2013-03-23 21:53 ` J-P. Rosen 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-23 10:19 UTC (permalink / raw) On Sat, 23 Mar 2013 10:02:11 +0100, J-P. Rosen wrote: > Le 23/03/2013 09:14, Dmitry A. Kazakov a �crit : >> declare >> X : Positive; >> begin >> X := -1; -- With Integer it behaves *differently* >> end; >> >> So, WHERE is the difference, what make the program above to work >> differently, if everything [value, type, operation] is SAME? > The values are the same, the subtype is a property of a variable. And an operation should *know* the properties of involved operands beyond values and types. Right? > The assignment behaves the same: check that the value belongs to the > allowed values for the variable, and raise C_E if not. Of course it is the same assignment, according to you. Why the effect is different? > The check > succeeds for some variables, and fails for others. This does not mean it > is a different operation. But the ultimate effect of the operation is different when check fails. > Once again: a subtype is just an extra check added in some contexts to > some objects. It does not define a new set of values, i.e. the "1" for > Positive is the same as the "1" for Integer (while it is different from > the "1" of some user defined type). And 0xFF is same for signed and unsigned char. This is why C is called weakly typed. It is no matter how do you call what is going on. Only the effect matters. The effect is that the behavior changes. Check is needed to be put somewhere. Programmers design programs in terms of values, operations and types. You can consider check an operation or a part of. You can consider check a part of the type which magically changes the behavior of operations defined on the type. In any case, it will have the effect of making some aspect of Positive different from Integer. Which makes it a different type. And this is clearly the intent of the programmer using Positive. Because otherwise he would use Integer. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-23 10:19 ` Dmitry A. Kazakov @ 2013-03-23 21:53 ` J-P. Rosen 2013-03-24 8:17 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: J-P. Rosen @ 2013-03-23 21:53 UTC (permalink / raw) Le 23/03/2013 11:19, Dmitry A. Kazakov a �crit : > Of course it is the same assignment, according to you. Why the effect is > different? Because it operates on different variables. Any subprogram that contains an "if" behaves differently depending on the parameters. It does not mean that each possible value of the parameters inherits a different subprogram. >> Once again: a subtype is just an extra check added in some contexts to >> some objects. It does not define a new set of values, i.e. the "1" for >> Positive is the same as the "1" for Integer (while it is different from >> the "1" of some user defined type). > > And 0xFF is same for signed and unsigned char. This is why C is called > weakly typed. It is no matter how do you call what is going on. Only the > effect matters. The effect is that the behavior changes. In C yes, there is only one integer type. Not in Ada. What's your point? -- J-P. Rosen Adalog 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00 http://www.adalog.fr ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-23 21:53 ` J-P. Rosen @ 2013-03-24 8:17 ` Dmitry A. Kazakov 2013-03-24 8:27 ` J-P. Rosen 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-24 8:17 UTC (permalink / raw) On Sat, 23 Mar 2013 22:53:15 +0100, J-P. Rosen wrote: > Le 23/03/2013 11:19, Dmitry A. Kazakov a �crit : >> Of course it is the same assignment, according to you. Why the effect is >> different? > Because it operates on different variables. How are they different? They have same name and same type (according to you) etc. Moreover, you want to tell that the behavior of an operation would depend on a variable? Do I read it right? Not on the type or value it has. This is how you want to deal with simple scalar types? > Any subprogram that contains > an "if" behaves differently depending on the parameters. There is no if's in the program. The program applies an operation to a variable. Nothing more. >>> Once again: a subtype is just an extra check added in some contexts to >>> some objects. It does not define a new set of values, i.e. the "1" for >>> Positive is the same as the "1" for Integer (while it is different from >>> the "1" of some user defined type). >> >> And 0xFF is same for signed and unsigned char. This is why C is called >> weakly typed. It is no matter how do you call what is going on. Only the >> effect matters. The effect is that the behavior changes. > In C yes, there is only one integer type. Not in Ada. Only one type for Integer and Positive, just as you said. > What's your point? Your interpretation of Ada subtypes is untyped. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-24 8:17 ` Dmitry A. Kazakov @ 2013-03-24 8:27 ` J-P. Rosen 2013-03-24 13:01 ` AdaMagica 2013-03-25 8:32 ` Dmitry A. Kazakov 0 siblings, 2 replies; 242+ messages in thread From: J-P. Rosen @ 2013-03-24 8:27 UTC (permalink / raw) Le 24/03/2013 09:17, Dmitry A. Kazakov a �crit : > Moreover, you want to tell that the behavior of an operation would depend > on a variable? Do I read it right? Not on the type or value it has. This is > how you want to deal with simple scalar types? Yes, the behaviour of assignment depends on the SUBTYPE of the target variable. >> Any subprogram that contains >> an "if" behaves differently depending on the parameters. > > There is no if's in the program. The program applies an operation to a > variable. Nothing more. There is a check => an implicit if > Your interpretation of Ada subtypes is untyped. > You are doing interpretations. I am reading the ARM Now, I think we have reached a point where nothing new can be added, and we are boring people. Let's agree that we don't agree and stop the thread. -- J-P. Rosen Adalog 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00 http://www.adalog.fr ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-24 8:27 ` J-P. Rosen @ 2013-03-24 13:01 ` AdaMagica 2013-03-25 8:32 ` Dmitry A. Kazakov 1 sibling, 0 replies; 242+ messages in thread From: AdaMagica @ 2013-03-24 13:01 UTC (permalink / raw) It's amazing how patient Randy and Jean-Pierre are with this paranoic discussion turning round in circles and never reaching an end because Dmitry always turns their words in their mouths. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-24 8:27 ` J-P. Rosen 2013-03-24 13:01 ` AdaMagica @ 2013-03-25 8:32 ` Dmitry A. Kazakov 2013-03-25 9:19 ` Georg Bauhaus 1 sibling, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-25 8:32 UTC (permalink / raw) On Sun, 24 Mar 2013 09:27:02 +0100, J-P. Rosen wrote: > Le 24/03/2013 09:17, Dmitry A. Kazakov a �crit : >> Moreover, you want to tell that the behavior of an operation would depend >> on a variable? Do I read it right? Not on the type or value it has. This is >> how you want to deal with simple scalar types? > Yes, the behaviour of assignment depends on the SUBTYPE of the target > variable. Merely in order to warn other readers of c.l.a. It is not a variable property and there exist cases when this matters. E.g. X : Integer := Positive'(-1); This must raise Constrant_Error, though X as an Integer variable does not have any constraint; though Positive allegedly has the value -1. But qualified expression disagrees. Another example where it does matter, that the constraint is not a property of the variable, is the behavior of X'Valid. We can trick the compiler to assign -1 to a Positive through the hole in the semantics of renaming and this will become a "valid" value of: with Ada.Text_IO; use Ada.Text_IO; procedure Test is X : Integer; Y : Positive renames X; begin Y := -1; Put_Line (Boolean'Image (Y'Valid)); end Test; TRUE is printed. [I don't know if Ada 2012 is going to fix this, e.g. considering range a "predicate"] > Now, I think we have reached a point where nothing new can be added, and > we are boring people. Let's agree that we don't agree and stop the thread. Yes. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-25 8:32 ` Dmitry A. Kazakov @ 2013-03-25 9:19 ` Georg Bauhaus 2013-03-25 10:08 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Georg Bauhaus @ 2013-03-25 9:19 UTC (permalink / raw) On 25.03.13 09:32, Dmitry A. Kazakov wrote: > On Sun, 24 Mar 2013 09:27:02 +0100, J-P. Rosen wrote: > >> Le 24/03/2013 09:17, Dmitry A. Kazakov a �crit : >>> Moreover, you want to tell that the behavior of an operation would depend >>> on a variable? Do I read it right? Not on the type or value it has. This is >>> how you want to deal with simple scalar types? >> Yes, the behaviour of assignment depends on the SUBTYPE of the target >> variable. > > Merely in order to warn other readers of c.l.a. It is not a variable > property and there exist cases when this matters. E.g. > > X : Integer := Positive'(-1); > > This must raise Constrant_Error, Yes. > though X as an Integer variable does not > have any constraint; Two things seem logically wrong, here, I think. 1. Ada's Standard.Integer has a constraint. Standard.Positive has a constraint that is different from Standard.Integer's constraint. Both, Integer and Positive, refer to the same Ada type, in Ada. 2. And no. Changing the situation by introducing qualified expression and representing J-P. Rosen's comment as if being about that situation (when it is not) does not kill the fact that, in Ada, a constraint error like the above one is not a type error. This has a type error, in Ada: X : Duration := Positive'(-1); So has this X : Duration := Positive'(1); If Constraint_Error is too weak for you, go ahead, rewrite the language, and really do so: If you want Positive to be a type, in Ada, and if it is easy to make it a type, in Ada---like you have outlined in just a few sentences, recently---do take the time to make the trivial adjustments to RM 3 etc, all paragraphs, add or remove paragraphs as needed, outline efforts needed for implementing, as you have done, and submit. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-25 9:19 ` Georg Bauhaus @ 2013-03-25 10:08 ` Dmitry A. Kazakov 0 siblings, 0 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-25 10:08 UTC (permalink / raw) On Mon, 25 Mar 2013 10:19:05 +0100, Georg Bauhaus wrote: > If Constraint_Error is too weak for you, go ahead, rewrite the language, ? I just give Ada-subtypes a well-typed interpretation, for those who enjoy to think about it in terms of strong typing. Others are free to use other interpretations [consistent with the language semantics]. They may have difficulties with that, but this is not my concern. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-19 10:14 ` Dmitry A. Kazakov 2013-03-19 14:23 ` Georg Bauhaus @ 2013-03-19 21:37 ` Randy Brukardt 2013-03-20 8:48 ` Dmitry A. Kazakov 1 sibling, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-03-19 21:37 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:vawvqtrqgamw$.1gsl8m14dvk4i.dlg@40tude.net... > On Mon, 18 Mar 2013 17:36:31 -0500, Randy Brukardt wrote: > >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >> news:hiybjkhz3p5d.1x6dxfr1ptgcg.dlg@40tude.net... > >>> But I don't see where I disagree with myself. Contract /= type. You can >>> have same contract and different types. What about: >>> >>> type Same is new Integer; >> >> This definitely has a different contract, as it is not compatible with >> Integer's contract. Yes, it has the same set of values and operations >> with >> the same name, profile, and bodies, but it's still a different contract >> because the types involved are an intergral part of the contract. > > See, you just defined a contract in terms of types while using contracts > to > define type as same/different/non-existent. You cannot have it in both > ways. If you can't handle recursive definitions, you'll never get very far in programming language design. The only requirement is that each step gets simpler, which certainly is the case here. >>> You also can have different contracts put on the same type in different >>> contexts. You can have contracts on something that does not involve >>> types >>> at all. Anyway, I fail to see how contracts are relevant here. >> >> Because types are an important part of a contract (that is, in Ada terms, >> the profile). > > *if* you want to contract a type, *then* that cannot be a part of. A type *has* a contract. A contract is made up (in part) of types. No problem. ... ... >> I agree with Georg; Positive is not a type; it *has* a type. Neither is >> Integer a type; it *has* a type. > > Since there is an equivalence between Positive and the type is "has," No, there is not any equivalence. "Type" is just one property of "Positive", and it might have the same value as that of some other subtype (like "Natural"). > Positive as a name unambiguously refers to that type, i.e. "Positive" is > the name of the type. Unless you have other legal name for it. But you > don't in Ada. You have absolutely no language means whatsoever to > distinguish Positive and the type of. So, what merits has this distinction > if it cannot be observed? "The type of Positive" unambigiously identifies that property for "Positive". There is not "name" (that is, identifier) associated with that property. >> (All types in Ada are anonymous.) > > Great, then let them be, where there belong to, in the celestial spheres, > and let us call type something that indeed exists in the language and has > a > name. Well, if you insist on naming the unnameable, you'll never reach any useful understanding. If you absolutely have to have a name, call it "the type of Positive" or "Positive'Base" (not all types have the 'Base attribute, or you could use that as the name). And Positive'Base = Integer'Base = Natural'Base. >> Types are only about static semantics >> (that is, compile-time behavior). Run-time semantics aren't involved. > > Run-time semantics is what makes program working or not working. Types are > all about run-time semantics nothing else counts. Then we really have nothing to talk about. > Type checks is a way to prove something about [run-time] semantics at > compile time. Types neither ensure nor required for a program to behave > correctly. They are a tool to ease reaching that goal. > >> Run-time semantics get added on top of that, but that has no effect on >> the >> legality of a program, so it is completely orthogonal to the >> type/profile. > > Legality is irrelevant as we consider only legal Ada programs. There exist > legal Ada programs which change their run-time behavior when 'Positive' is > replaced by 'Integer' and reverse. "We consider only legal Ada programs" -- please speak for yourself. What is in or not in that set of legal Ada programs is a very important part of Ada's design (and any language design). I'm not particularly interested in the run-time semantics of scalar types, because it is pretty much that of the hardware and no amount of language design is going to change that. The only thing we can tweak is what is legal and illegal. It's pretty obvious that you have no interest in useful discourse on this topic (which is really too bad, because you have interesting ideas that could help out Ada in the long run), so I'm going to do my best to ignore this thread in the future. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-19 21:37 ` Randy Brukardt @ 2013-03-20 8:48 ` Dmitry A. Kazakov 0 siblings, 0 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-20 8:48 UTC (permalink / raw) On Tue, 19 Mar 2013 16:37:30 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:vawvqtrqgamw$.1gsl8m14dvk4i.dlg@40tude.net... >> On Mon, 18 Mar 2013 17:36:31 -0500, Randy Brukardt wrote: >> >>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >>> news:hiybjkhz3p5d.1x6dxfr1ptgcg.dlg@40tude.net... >> >>>> But I don't see where I disagree with myself. Contract /= type. You can >>>> have same contract and different types. What about: >>>> >>>> type Same is new Integer; >>> >>> This definitely has a different contract, as it is not compatible with >>> Integer's contract. Yes, it has the same set of values and operations >>> with the same name, profile, and bodies, but it's still a different contract >>> because the types involved are an intergral part of the contract. >> >> See, you just defined a contract in terms of types while using contracts to >> define type as same/different/non-existent. You cannot have it in both >> ways. > > If you can't handle recursive definitions, you'll never get very far in > programming language design. Still, the definition you used is broken. Mine is not. >>>> You also can have different contracts put on the same type in different >>>> contexts. You can have contracts on something that does not involve types >>>> at all. Anyway, I fail to see how contracts are relevant here. >>> >>> Because types are an important part of a contract (that is, in Ada terms, >>> the profile). >> >> *if* you want to contract a type, *then* that cannot be a part of. > > A type *has* a contract. A contract is made up (in part) of types. 1. *Other* types. 2. To have a contract /= be a part of. >>> I agree with Georg; Positive is not a type; it *has* a type. Neither is >>> Integer a type; it *has* a type. >> >> Since there is an equivalence between Positive and the type is "has," > > No, there is not any equivalence. "Type" is just one property of "Positive", > and it might have the same value as that of some other subtype (like > "Natural"). The equivalence http://en.wikipedia.org/wiki/Equivalence_relation is that for each Ada-subtype S there exists a corresponding Ada-type T, and conversely for each T there exists S. >> Positive as a name unambiguously refers to that type, i.e. "Positive" is >> the name of the type. Unless you have other legal name for it. But you >> don't in Ada. You have absolutely no language means whatsoever to >> distinguish Positive and the type of. So, what merits has this distinction >> if it cannot be observed? > > "The type of Positive" unambigiously identifies that property for > "Positive". There is not "name" (that is, identifier) associated with that > property. ... and there is no way you could find any difference. >>> (All types in Ada are anonymous.) >> >> Great, then let them be, where there belong to, in the celestial spheres, >> and let us call type something that indeed exists in the language and has >> a name. > > Well, if you insist on naming the unnameable, you'll never reach any useful > understanding. If you absolutely have to have a name, call it "the type of > Positive" or "Positive'Base" (not all types have the 'Base attribute, or you > could use that as the name). > > And Positive'Base = Integer'Base = Natural'Base. But Positive /= Integer /= Natural Your theory simply does not reflect language facts, thus it is a wrong theory. >>> Run-time semantics get added on top of that, but that has no effect on >>> the legality of a program, so it is completely orthogonal to the >>> type/profile. >> >> Legality is irrelevant as we consider only legal Ada programs. There exist >> legal Ada programs which change their run-time behavior when 'Positive' is >> replaced by 'Integer' and reverse. > > "We consider only legal Ada programs" -- please speak for yourself. Yes, I am a programmer, I am not interested in illegal programs. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-14 14:26 ` Dmitry A. Kazakov 2013-03-14 14:57 ` Georg Bauhaus 2013-03-14 16:21 ` J-P. Rosen @ 2013-03-14 16:22 ` Shark8 2013-03-14 17:08 ` Dmitry A. Kazakov 2 siblings, 1 reply; 242+ messages in thread From: Shark8 @ 2013-03-14 16:22 UTC (permalink / raw) Cc: mailbox On Thursday, March 14, 2013 8:26:56 AM UTC-6, Dmitry A. Kazakov wrote: > On Thu, 14 Mar 2013 13:37:44 +0100, Georg Bauhaus wrote: > > >> We don't talk about Positive'Base. We do about Positive. > > > > Positive'Succ does *not* declare parameters whose subtype is Positive. > > Surely it does. Proof: > > X : Positive := 1; > Y : Positive := Positive'Succ (X); > > Either Ada is untyped or else Positive'Succ is effectively defined on > Positive and returns Positive. Objection! The LRM says this about Types and Subtypes in 3.2 (8/2): A subtype of a given type is a combination of the type, a constraint on values of the type, and certain attributes specific to the subtype. The given type is called the type of the subtype. Similarly, the associated constraint is called the constraint of the subtype. The set of values of a subtype consists of the values of its type that satisfy its constraint and any exclusion of the null value. Such values belong to the subtype. So then the TYPE of Positive is it's base, Integer (even if declared as a subtype of Natural, precisely because the TYPE of natural would also be Integer). If the parameters and results of 'Succ & 'Pred are of 'Base then they must obviously be able to take parameters of the given [SUB]TYPE because it's TYPE *is* 'Base. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-14 16:22 ` Shark8 @ 2013-03-14 17:08 ` Dmitry A. Kazakov 0 siblings, 0 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-14 17:08 UTC (permalink / raw) On Thu, 14 Mar 2013 09:22:40 -0700 (PDT), Shark8 wrote: > On Thursday, March 14, 2013 8:26:56 AM UTC-6, Dmitry A. Kazakov wrote: >> On Thu, 14 Mar 2013 13:37:44 +0100, Georg Bauhaus wrote: >> >>>> We don't talk about Positive'Base. We do about Positive. >>> >>> Positive'Succ does *not* declare parameters whose subtype is Positive. >> >> Surely it does. Proof: >> >> X : Positive := 1; >> Y : Positive := Positive'Succ (X); >> >> Either Ada is untyped or else Positive'Succ is effectively defined on >> Positive and returns Positive. > > Objection! [...] The code is before your eyes. Operation is called on a Positive => Positive has this operation. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 19:28 ` Dmitry A. Kazakov 2013-03-13 21:01 ` Randy Brukardt 2013-03-13 21:37 ` Georg Bauhaus @ 2013-03-13 22:34 ` Robert A Duff 2013-03-14 9:09 ` Dmitry A. Kazakov 2 siblings, 1 reply; 242+ messages in thread From: Robert A Duff @ 2013-03-13 22:34 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > Ada's design choice was in favor of Integer's order: 'Succ (3)=4. But > user's expectation was the order from the problem space 'Succ(3)=5. As a user, what is your expectation for the following? X : Prime := 3; A : Integer := Prime'Succ (X); -- A = 4 B : Integer := Integer'Succ (X); -- B = 4 C : Integer := X + 1; -- C = 4 D : Prime := X + 1; -- Constraint_Error on the ":=", not on the "+" E : Integer := Positive'Pred(1); -- E = 0 F : Integer := Positive'Pred(-100); -- F = -101 type T is range 1..10; G : T := 10; H : T := 10; I : T := (G + H) / 2; -- I = 10 I've shown the actual Ada semantics in comments. Does your expectation differ? (Nitpick: The expression G+H could overflow, if the compiler chose a base range for T of -10..10. No compiler does that, but if you're worried about it, you could declare "type T is new Integer range 1..10" instead.) - Bob ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 22:34 ` Robert A Duff @ 2013-03-14 9:09 ` Dmitry A. Kazakov 2013-03-14 9:27 ` Georg Bauhaus 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-14 9:09 UTC (permalink / raw) On Wed, 13 Mar 2013 18:34:35 -0400, Robert A Duff wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > >> Ada's design choice was in favor of Integer's order: 'Succ (3)=4. But >> user's expectation was the order from the problem space 'Succ(3)=5. > > As a user, what is your expectation for the following? My expectation is that the language should not let me doing this without requesting explicit specification of which interfaces and implementations get inherited. Prime is clearly not integer, so if I inherit from it publicly while applying some constraint which is not a range, I must be required to override all numeric operations, all relational operations, all operations that depends on ordering IF I want them. But the default if, there should be any, must be no such operations inherited. There is too much going under the carpet, which is wrong. Ada must have explicit interfaces manifested. RM 3.5.5, 3.5.8, 3.5.10 etc are nothing but descriptions of interfaces. They shall have names. And it must be said that a declaration like type T is range A..B; is a shortcut for a more explicit declaration of T inheriting interfaces of a scalar object, a comparable object, a numeric object, an ordered object, a copyiable object etc. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-14 9:09 ` Dmitry A. Kazakov @ 2013-03-14 9:27 ` Georg Bauhaus 0 siblings, 0 replies; 242+ messages in thread From: Georg Bauhaus @ 2013-03-14 9:27 UTC (permalink / raw) On 14.03.13 10:09, Dmitry A. Kazakov wrote: > And it must be said that > a declaration like > > type T is range A..B; > > is a shortcut for a more explicit declaration of T inheriting interfaces of > a scalar object, a comparable object, a numeric object, an ordered object, > a copyiable object etc. +1 With the proviso that the compatibility obstacle requires restraint, I'd suggest type R is abstract range 0 .. 1; type T is abstract new Float; as a starting point. Is "abstract ..." compatible with previous versions of the language? ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 14:34 ` Georg Bauhaus 2013-03-13 15:51 ` Dmitry A. Kazakov @ 2013-03-13 17:05 ` Shark8 2013-03-13 17:45 ` Simon Wright 1 sibling, 1 reply; 242+ messages in thread From: Shark8 @ 2013-03-13 17:05 UTC (permalink / raw) On Wednesday, March 13, 2013 8:34:41 AM UTC-6, Georg Bauhaus wrote: > > External observations inspired by whichever type theory do > not apply when judging things from the Ada perspective. > I'd find observations interesting only when someone is pondering > language design, not when explaining properties of an existing > language. Randy mentioned a time machine... I don't know, I think that if I could alter the the past (Ada 83) for some minor alterations it would be to include null-exclusion on access types... seems like that would have been far more useful in-practice than mucking about with 'Pred/'Succ or 'First/'Last. -- child packages would have been nice from the inception, but I don't think the compiler-writers would have tolerated the added complexity there given that as it was Ada 83 was pushing the bleeding-edge bounds of compiler technology. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 17:05 ` Shark8 @ 2013-03-13 17:45 ` Simon Wright 2013-03-13 19:37 ` Dmitry A. Kazakov 2013-03-14 22:41 ` Florian Weimer 0 siblings, 2 replies; 242+ messages in thread From: Simon Wright @ 2013-03-13 17:45 UTC (permalink / raw) Shark8 <onewingedshark@gmail.com> writes: > On Wednesday, March 13, 2013 8:34:41 AM UTC-6, Georg Bauhaus wrote: >> >> External observations inspired by whichever type theory do >> not apply when judging things from the Ada perspective. >> I'd find observations interesting only when someone is pondering >> language design, not when explaining properties of an existing >> language. Randy mentioned a time machine... > > I don't know, I think that if I could alter the the past (Ada 83) for > some minor alterations it would be to include null-exclusion on access > types... seems like that would have been far more useful in-practice > than mucking about with 'Pred/'Succ or 'First/'Last. -- child packages > would have been nice from the inception, but I don't think the > compiler-writers would have tolerated the added complexity there given > that as it was Ada 83 was pushing the bleeding-edge bounds of compiler > technology. I don't remember ever using 'Pred/'Succ, but I'd sorely miss 'First/'Last. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 17:45 ` Simon Wright @ 2013-03-13 19:37 ` Dmitry A. Kazakov 2013-03-13 19:54 ` Simon Wright 2013-03-13 21:09 ` Randy Brukardt 2013-03-14 22:41 ` Florian Weimer 1 sibling, 2 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-13 19:37 UTC (permalink / raw) On Wed, 13 Mar 2013 17:45:56 +0000, Simon Wright wrote: > I don't remember ever using 'Pred/'Succ, Even in: generic type Discrete is (<>); package Foo is ? Well, you could use Discrete'Val (Discrete'Pos (Index) + 1) as a substitute for Discrete'Succ (Index). -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 19:37 ` Dmitry A. Kazakov @ 2013-03-13 19:54 ` Simon Wright 2013-03-13 20:54 ` Dmitry A. Kazakov 2013-03-13 21:47 ` Jeffrey Carter 2013-03-13 21:09 ` Randy Brukardt 1 sibling, 2 replies; 242+ messages in thread From: Simon Wright @ 2013-03-13 19:54 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > On Wed, 13 Mar 2013 17:45:56 +0000, Simon Wright wrote: > >> I don't remember ever using 'Pred/'Succ, > > Even in: > > generic > type Discrete is (<>); > package Foo is Nope. Out of over 200 packages I have only one with this construct: it is a signature package, no need for 'Pred or 'Succ (in other words, the enumeration defines a set of distinct possibilities, ordering irrelevant). generic -- This package specifies the properties required of a Time for it -- to be used with event management. type Time_Kind is (<>); -- One of the kinds of Time must be Real_Time, used for "delay for". Real_Time : Time_Kind; type Time (Kind : Time_Kind) is private; with function From_Now (Period : Duration) return Time; with function Image (Of_Time : Time) return String; -- Used in logging versions of Event Queues. package ColdFrame.Time_Signature is end ColdFrame.Time_Signature; ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 19:54 ` Simon Wright @ 2013-03-13 20:54 ` Dmitry A. Kazakov 2013-03-13 21:28 ` Simon Wright 2013-03-13 22:12 ` Robert A Duff 2013-03-13 21:47 ` Jeffrey Carter 1 sibling, 2 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-13 20:54 UTC (permalink / raw) On Wed, 13 Mar 2013 19:54:22 +0000, Simon Wright wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > >> On Wed, 13 Mar 2013 17:45:56 +0000, Simon Wright wrote: >> >>> I don't remember ever using 'Pred/'Succ, >> >> Even in: >> >> generic >> type Discrete is (<>); >> package Foo is > > Nope. > > Out of over 200 packages I have only one with this construct: it is a > signature package, no need for 'Pred or 'Succ (in other words, the > enumeration defines a set of distinct possibilities, ordering > irrelevant). You need (<>) as an ancestor of both mod <> and range <> in packages that should be instantiated with either integer or modular type. Ada needs explicit interfaces, so that you could declare an unordered enumeration if you don't need order. However, from the practical perspective that would be public view, privately you still need it ordered in some ad-hoc way to be able to implement stream attributes, hash tables etc. P.S. This is how Ada could finally get curly brackets (:-)): type Color is {Red, Green, Blue}; -- No order in public views -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 20:54 ` Dmitry A. Kazakov @ 2013-03-13 21:28 ` Simon Wright 2013-03-14 9:16 ` Dmitry A. Kazakov 2013-03-13 22:12 ` Robert A Duff 1 sibling, 1 reply; 242+ messages in thread From: Simon Wright @ 2013-03-13 21:28 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > On Wed, 13 Mar 2013 19:54:22 +0000, Simon Wright wrote: > >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: >> >>> On Wed, 13 Mar 2013 17:45:56 +0000, Simon Wright wrote: >>> >>>> I don't remember ever using 'Pred/'Succ, >>> >>> Even in: >>> >>> generic >>> type Discrete is (<>); >>> package Foo is >> >> Nope. >> >> Out of over 200 packages I have only one with this construct: it is a >> signature package, no need for 'Pred or 'Succ (in other words, the >> enumeration defines a set of distinct possibilities, ordering >> irrelevant). > > You need (<>) as an ancestor of both mod <> and range <> in packages > that should be instantiated with either integer or modular type. I don't understand this. Anyway, as I said, only 0.5% of the packages I have written (and that I have on this machine) have a formal discrete type definition, and 'Pred/'Succ were irrelevant for that one. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 21:28 ` Simon Wright @ 2013-03-14 9:16 ` Dmitry A. Kazakov 2013-03-14 16:42 ` Simon Wright 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-14 9:16 UTC (permalink / raw) On Wed, 13 Mar 2013 21:28:03 +0000, Simon Wright wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > >> On Wed, 13 Mar 2013 19:54:22 +0000, Simon Wright wrote: >> >>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: >>> >>>> On Wed, 13 Mar 2013 17:45:56 +0000, Simon Wright wrote: >>>> >>>>> I don't remember ever using 'Pred/'Succ, >>>> >>>> Even in: >>>> >>>> generic >>>> type Discrete is (<>); >>>> package Foo is >>> >>> Nope. >>> >>> Out of over 200 packages I have only one with this construct: it is a >>> signature package, no need for 'Pred or 'Succ (in other words, the >>> enumeration defines a set of distinct possibilities, ordering >>> irrelevant). >> >> You need (<>) as an ancestor of both mod <> and range <> in packages >> that should be instantiated with either integer or modular type. > > I don't understand this. Let you have a generic package you wanted to be able o instantiate with either Unsigned_16 or Integer. The formal generic type for that is formal discrete. E.g. generic type Index_Type is (<>); type Element_Type is private; package Generic_Array is ... -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-14 9:16 ` Dmitry A. Kazakov @ 2013-03-14 16:42 ` Simon Wright 2013-03-14 17:05 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Simon Wright @ 2013-03-14 16:42 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > On Wed, 13 Mar 2013 21:28:03 +0000, Simon Wright wrote: > >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: >> >>> You need (<>) as an ancestor of both mod <> and range <> in packages >>> that should be instantiated with either integer or modular type. >> >> I don't understand this. > > Let you have a generic package you wanted to be able o instantiate with > either Unsigned_16 or Integer. The formal generic type for that is formal > discrete. E.g. > > generic > type Index_Type is (<>); > type Element_Type is private; > package Generic_Array is ... Oh. When you used the word 'ancestor' I thought you were talking about inheritance or type derivation. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-14 16:42 ` Simon Wright @ 2013-03-14 17:05 ` Dmitry A. Kazakov 0 siblings, 0 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-14 17:05 UTC (permalink / raw) On Thu, 14 Mar 2013 16:42:24 +0000, Simon Wright wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > >> On Wed, 13 Mar 2013 21:28:03 +0000, Simon Wright wrote: >> >>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: >>> >>>> You need (<>) as an ancestor of both mod <> and range <> in packages >>>> that should be instantiated with either integer or modular type. >>> >>> I don't understand this. >> >> Let you have a generic package you wanted to be able o instantiate with >> either Unsigned_16 or Integer. The formal generic type for that is formal >> discrete. E.g. >> >> generic >> type Index_Type is (<>); >> type Element_Type is private; >> package Generic_Array is ... > > Oh. When you used the word 'ancestor' I thought you were talking about > inheritance or type derivation. That is same. Generic formal types form a class. The class (<>) includes both the class range <> and the class mod <>. In this sense is it an ancestor similarly how a tagged parent type or a base type is for a derived type. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 20:54 ` Dmitry A. Kazakov 2013-03-13 21:28 ` Simon Wright @ 2013-03-13 22:12 ` Robert A Duff 1 sibling, 0 replies; 242+ messages in thread From: Robert A Duff @ 2013-03-13 22:12 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > P.S. This is how Ada could finally get curly brackets (:-)): > > type Color is {Red, Green, Blue}; -- No order in public views An early version of Ada (Green?) had unordered enumeration types. I don't remember the syntax, but it didn't involve curly braces. ;-) GNAT has a pragma Ordered to mark an enumeration type as ordered, and a switch -gnatw.u that tells the compiler to complain if you use certain operations on unordered enums (unordered being the default). - Bob ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 19:54 ` Simon Wright 2013-03-13 20:54 ` Dmitry A. Kazakov @ 2013-03-13 21:47 ` Jeffrey Carter 1 sibling, 0 replies; 242+ messages in thread From: Jeffrey Carter @ 2013-03-13 21:47 UTC (permalink / raw) On 03/13/2013 12:54 PM, Simon Wright wrote: > > Out of over 200 packages I have only one with this construct: it is a > signature package, no need for 'Pred or 'Succ (in other words, the > enumeration defines a set of distinct possibilities, ordering > irrelevant). The sorting algorithms in the PragmAda Reusable Components have a generic formal part like generic -- PragmARC.Sort_Heap type Element is private; type Index is (<>); type Sort_Set is array (Index range <>) of Element; with function "<" (Left : Element; Right : Element) return Boolean is <>; procedure PragmARC.Sort_Heap (Set : in out Sort_Set); and use Index'Pred and Index'Succ. -- Jeff Carter "Ah, go away or I'll kill ya." Never Give a Sucker an Even Break 100 ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 19:37 ` Dmitry A. Kazakov 2013-03-13 19:54 ` Simon Wright @ 2013-03-13 21:09 ` Randy Brukardt 2013-03-13 22:48 ` Shark8 1 sibling, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-03-13 21:09 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:11rcs3gg4taww$.bylek8fsshyz$.dlg@40tude.net... > On Wed, 13 Mar 2013 17:45:56 +0000, Simon Wright wrote: > >> I don't remember ever using 'Pred/'Succ, > > Even in: > > generic > type Discrete is (<>); > package Foo is > > ? I'm not Simon, but in generics I've only used loops on discrete types (the usual reason for such a type being to index an array). In almost all other cases, I've ended up taking 'Pos on them because real math was needed (masking, usually). The not-defined procedure 'Succ would have been much more useful because it could replace expressions like: <Very_Long_Name> := <Very_Long_Name> + 1; with <Very_Long_Name>'Succ; which would eliminate the potential for errors, possibly generate better code (by not having to evaluate <Very_Long_Name> twice if it contains function calls), and eliminate the hair-brained calls for ":=+" operators (which don't even work for Ada). Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 21:09 ` Randy Brukardt @ 2013-03-13 22:48 ` Shark8 2013-03-14 22:01 ` Randy Brukardt 0 siblings, 1 reply; 242+ messages in thread From: Shark8 @ 2013-03-13 22:48 UTC (permalink / raw) On Wednesday, March 13, 2013 3:09:24 PM UTC-6, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > > news:11rcs3gg4taww$.bylek8fsshyz$.dlg@40tude.net... > > > On Wed, 13 Mar 2013 17:45:56 +0000, Simon Wright wrote: > > > >> I don't remember ever using 'Pred/'Succ, > > > > Even in: > > generic > > type Discrete is (<>); > > package Foo is > > ? > > I'm not Simon, but in generics I've only used loops on discrete types (the > usual reason for such a type being to index an array). In almost all other > cases, I've ended up taking 'Pos on them because real math was needed > (masking, usually). > > The not-defined procedure 'Succ would have been much more useful because it > could replace expressions like: > > <Very_Long_Name> := <Very_Long_Name> + 1; > with > <Very_Long_Name>'Succ; > > which would eliminate the potential for errors, possibly generate better > code (by not having to evaluate <Very_Long_Name> twice if it contains > function calls), and eliminate the hair-brained calls for ":=+" operators > (which don't even work for Ada). > Would there be a problem using this? Generic Type T is (<>); with function Succ(Input : T) Return T is T'Succ; package Test is -- Body does whatever is needed requiring Very_Long_Name as T. end Test; ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 22:48 ` Shark8 @ 2013-03-14 22:01 ` Randy Brukardt 2013-03-15 3:27 ` Shark8 0 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-03-14 22:01 UTC (permalink / raw) "Shark8" <onewingedshark@gmail.com> wrote in message news:99929f93-b80f-47c3-8a37-c81002733754@googlegroups.com... > On Wednesday, March 13, 2013 3:09:24 PM UTC-6, Randy Brukardt wrote: ... >> The not-defined procedure 'Succ would have been much more useful because >> it >> could replace expressions like: >> >> <Very_Long_Name> := <Very_Long_Name> + 1; >> with >> <Very_Long_Name>'Succ; >> >> which would eliminate the potential for errors, possibly generate better >> code (by not having to evaluate <Very_Long_Name> twice if it contains >> function calls), and eliminate the hair-brained calls for ":=+" operators >> (which don't even work for Ada). >> > > Would there be a problem using this? > > Generic > Type T is (<>); > with function Succ(Input : T) Return T is T'Succ; > package Test is > -- Body does whatever is needed requiring Very_Long_Name as T. > end Test; I don't see how this would work. You need to be able to use it on multiple <Very_Long_Name>s in order to make it worth the effort. Something like: generic type T is (<>); procedure Succ (Obj : in out T; Count : in Natural := 1) is -- Note: I know this requires a separate spec! begin for I in 1 .. Count loop Obj := T'Succ(Obj); end loop; end Succ; would match the intended attribute semantically. But it doesn't help much, because you have to write the generic somewhere, and then you have to instantiate it when you need it as well. That's not very helpful for what is intended to be a short-cut (you usually would end up typing more). The big advantage of an object attribute (like this 'Succ or GNAT's 'Img) is that you don't have to figure out the nominal subtype of the object to increment it once (which you do to write an instance of my Succ generic). Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-14 22:01 ` Randy Brukardt @ 2013-03-15 3:27 ` Shark8 2013-03-15 21:05 ` Randy Brukardt 0 siblings, 1 reply; 242+ messages in thread From: Shark8 @ 2013-03-15 3:27 UTC (permalink / raw) On Thursday, March 14, 2013 4:01:03 PM UTC-6, Randy Brukardt wrote: > "Shark8" <onewingedshark@gmail.com> wrote in message > news:99929f93-b80f-47c3-8a37-c81002733754@googlegroups.com... > > > > > Would there be a problem using this? > > Generic > > Type T is (<>); > > with function Succ(Input : T) Return T is T'Succ; > > package Test is > > -- Body does whatever is needed requiring Very_Long_Name as T. > > end Test; > > I don't see how this would work. You need to be able to use it on multiple > <Very_Long_Name>s in order to make it worth the effort. Er, wouldn't the function Succ be applicable to all Very_Long_Name items inside the package? > > Something like: > > generic > type T is (<>); > procedure Succ (Obj : in out T; Count : in Natural := 1) is -- Note: I > know this requires a separate spec! > begin > for I in 1 .. Count loop > Obj := T'Succ(Obj); > end loop; > end Succ; > > would match the intended attribute semantically. > > > But it doesn't help much, because you have to write the generic somewhere, > and then you have to instantiate it when you need it as well. That's not > very helpful for what is intended to be a short-cut (you usually would end > up typing more). The big advantage of an object attribute (like this 'Succ > or GNAT's 'Img) is that you don't have to figure out the nominal subtype of > the object to increment it once (which you do to write an instance of my > Succ generic). Hm, true; speaking of object-attributes I sometimes [though not too often] wish I could write something like: Procedure X( Input : Some_Type ) is Temp : Input'Type := Some_Value; begin -- Whatever needs done. end X; Is there any reason that should be disallowed / would be difficult for compiler-writers to implement? ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-15 3:27 ` Shark8 @ 2013-03-15 21:05 ` Randy Brukardt 2013-03-15 21:46 ` Robert A Duff 0 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-03-15 21:05 UTC (permalink / raw) "Shark8" <onewingedshark@gmail.com> wrote in message news:87ec4b1d-f7cd-49a4-8cff-d44aeb76a1ad@googlegroups.com... ... > Hm, true; speaking of object-attributes I sometimes [though not too often] > wish I could write something like: > Procedure X( Input : Some_Type ) is > Temp : Input'Type := Some_Value; > begin > -- Whatever needs done. > end X; > > Is there any reason that should be disallowed / would be difficult for > compiler-writers to implement? I've occassionally had such a thought, too. Probably the reason this doesn't exist is that Ada 83 didn't have type-valued attributes and thus it wasn't considered there. ('Base could only be used as an attribute prefix in Ada 83). There would potentially be a cost to an object attribute vs. using the subtype name directly, in that the prefix would have to be evaluated (which, if it included function calls or checks, would generate some code). I suppose there might be a problem in that this would provide a way to give a name to anonymous types. Most of the Ada rules presume that such types can't be named and thus can't be used in contexts where a name is required (like explicit type conversions). So there might be some problems raised by that; probably not insurmountable but makes it harder than trivial (in which case all of the trade-offs have to be considered - and given that the new capability here is either low or not desired - depending on your point of view - that makes it unlikely). What I'm talking about is something like: procedure P (A : access Int) is Obj : A'Type; -- A second object of a single anonymous type, not possible now. begin Obj := A'Type(Some_Ptr); -- An explicit conversion to an anonymous access type, not possible now. end P; It's not clear that there is any problem here, it's just that we haven't considered it and usually that means there is a problem there. :-) Could just be FUD, too. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-15 21:05 ` Randy Brukardt @ 2013-03-15 21:46 ` Robert A Duff 2013-03-16 5:52 ` Shark8 2013-03-16 9:29 ` Georg Bauhaus 0 siblings, 2 replies; 242+ messages in thread From: Robert A Duff @ 2013-03-15 21:46 UTC (permalink / raw) "Randy Brukardt" <randy@rrsoftware.com> writes: > "Shark8" <onewingedshark@gmail.com> wrote in message > news:87ec4b1d-f7cd-49a4-8cff-d44aeb76a1ad@googlegroups.com... > ... >> Hm, true; speaking of object-attributes I sometimes [though not too often] >> wish I could write something like: >> Procedure X( Input : Some_Type ) is >> Temp : Input'Type := Some_Value; >> begin >> -- Whatever needs done. >> end X; >> >> Is there any reason that should be disallowed / would be difficult for >> compiler-writers to implement? > > I've occassionally had such a thought, too. Me, too. (I also agree with Shark8's "not too often" comment.) Many languages allow the type of an object to be deduced from its initial value. I believe C++ recently added that feature, using the "auto" keyword (which it inherited from C, and meant something completely different -- and completely useless). Ada allows that in a small way -- named numbers. >... Probably the reason this doesn't > exist is that Ada 83 didn't have type-valued attributes and thus it wasn't > considered there. I suspect the reason was that the designers of Ada 83 thought that types of things ought to be explicit. Except for named numbers -- consistency wasn't their strong suit. > 83). There would potentially be a cost to an object attribute vs. using the > subtype name directly, in that the prefix would have to be evaluated (which, > if it included function calls or checks, would generate some code). Such cases could be forbidden. Or one could do something like what C does for sizeof -- the operand is not evaluated. It's as if you could say "X.all'Size" in Ada and not get a C_E, even if X = null. That works in C because all sizes are known at compile time. In Ada, all types are known at compile time, so "X.all'Type" (or "X.all'Subtype"?) could conceivably denote Integer even when X = null. > It's not clear that there is any problem here, it's just that we haven't > considered it and usually that means there is a problem there. :-) Could > just be FUD, too. Well, a bit of FUD is often appropriate in language design. ;-) - Bob ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-15 21:46 ` Robert A Duff @ 2013-03-16 5:52 ` Shark8 2013-03-16 7:41 ` Dmitry A. Kazakov 2013-03-16 20:45 ` Robert A Duff 2013-03-16 9:29 ` Georg Bauhaus 1 sibling, 2 replies; 242+ messages in thread From: Shark8 @ 2013-03-16 5:52 UTC (permalink / raw) On Friday, March 15, 2013 3:46:26 PM UTC-6, Robert A Duff wrote: > "Randy Brukardt" <randy@rrsoftware.com> writes: > > > "Shark8" <onewingedshark@gmail.com> wrote in message > > news:87ec4b1d-f7cd-49a4-8cff-d44aeb76a1ad@googlegroups.com... > > ... > >> Hm, true; speaking of object-attributes I sometimes [though not too often] > >> wish I could write something like: > >> Procedure X( Input : Some_Type ) is > >> Temp : Input'Type := Some_Value; > >> begin > >> -- Whatever needs done. > >> end X; > >> > >> Is there any reason that should be disallowed / would be difficult for > >> compiler-writers to implement? > > > > I've occassionally had such a thought, too. > > Me, too. (I also agree with Shark8's "not too often" comment.) > > > Many languages allow the type of an object to be deduced from > its initial value. I believe C++ recently added that feature, > using the "auto" keyword (which it inherited from C, and meant > something completely different -- and completely useless). > Ada allows that in a small way -- named numbers. This isn't _quite_ the same, it's declaring an object to be of the same type as some other (and already known) object. > >... Probably the reason this doesn't > > exist is that Ada 83 didn't have type-valued attributes and thus it wasn't > > considered there. > > I suspect the reason was that the designers of Ada 83 thought that > types of things ought to be explicit. Except for named numbers -- > consistency wasn't their strong suit. I thought that named numbers were of the Universal_Integer (if integral) or Universal_Float_and_Fixed if not... of course that could just be an incorrect notion I've developed. > > > 83). There would potentially be a cost to an object attribute vs. using the > > subtype name directly, in that the prefix would have to be evaluated (which, > > if it included function calls or checks, would generate some code). > > Such cases could be forbidden. True; but there could be some more interesting cases, say, for Ada 2020. Something like: Abstract Type UNIVERSAL_STRING(Element : UNIVERSAL_CHARACTER) is Array(Positive Range <>) of Element'Type; {Or something similar; if we did that we could conceivably be able to fold Strings, Wide_Strings, and Wide_Wide_Strings together having those packages in essence become instances of a GENERIC_STRING package... it would likely have a monstrous amount of parameters, for functions like To_Upper and To_Lower.} > > It's not clear that there is any problem here, it's just that we haven't > > considered it and usually that means there is a problem there. :-) Could > > just be FUD, too. > > Well, a bit of FUD is often appropriate in language design. ;-) This is very true; though given the haphazard approach some languages have to design *cough*PHP*cough* one might be tempted to think there's no thought given to design at all. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-16 5:52 ` Shark8 @ 2013-03-16 7:41 ` Dmitry A. Kazakov 2013-03-16 16:55 ` Shark8 2013-03-16 20:45 ` Robert A Duff 1 sibling, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-16 7:41 UTC (permalink / raw) On Fri, 15 Mar 2013 22:52:02 -0700 (PDT), Shark8 wrote: > True; but there could be some more interesting cases, say, for Ada 2020. > Something like: > > Abstract Type UNIVERSAL_STRING(Element : UNIVERSAL_CHARACTER) is > Array(Positive Range <>) of Element'Type; That would not work. I presume that here you want to create a root type for the class of string types and get at the members of the class (specific types like Wide_String) using a constraint. The problem is that string types must have different representations. The mechanism of constraining does not support. Thus either subtypes will have same representation or you won't have a class. Another problem is that string types must have more than one interface to deal with UTF-8 etc. An UTF-8 string is *both* an array of Wide_Wide_Character (= Unicode code points) and an array or sequence of Character (octets). An UTF-16 string is an array of Wide_Wide_Character and an array of Wide_String. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-16 7:41 ` Dmitry A. Kazakov @ 2013-03-16 16:55 ` Shark8 2013-03-16 17:36 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Shark8 @ 2013-03-16 16:55 UTC (permalink / raw) Cc: mailbox On Saturday, March 16, 2013 1:41:27 AM UTC-6, Dmitry A. Kazakov wrote: > On Fri, 15 Mar 2013 22:52:02 -0700 (PDT), Shark8 wrote: > > > True; but there could be some more interesting cases, say, for Ada 2020. > > Something like: > > > > Abstract Type UNIVERSAL_STRING(Element : UNIVERSAL_CHARACTER) is > > Array(Positive Range <>) of Element'Type; > > That would not work. I presume that here you want to create a root type for > the class of string types and get at the members of the class (specific > types like Wide_String) using a constraint. The problem is that string > types must have different representations. The mechanism of constraining > does not support. Kind of, but not really; I'm thinking a sort of combination of generics and classes (in the general sense, not the OOP-sense): a way to specify a general behavior for a type-class. (i.e. having the ability to fully-specify things like attributes [not really shown in this example].) > Thus either subtypes will have same representation or you > won't have a class. I'm thinking of it more in the terms of generic operations: independent of representation. > Another problem is that string types must have more > than one interface to deal with UTF-8 etc. An UTF-8 string is *both* an > array of Wide_Wide_Character (= Unicode code points) and an array or > sequence of Character (octets). Ah, things get tricky here; Unicode is kind of a bear when you consider 'characters' because its codepoints aren't necessarily characters. An example would be the so-called "combining characters" which you can use for things like accents or ZALGO-text. (See these, respectively: http://en.wikipedia.org/wiki/Combining_character and, http://eeemo.net/ ) An important implication of this is that string search/manipulation becomes MUCH more complex. (`+a = à) means that you now have to search for multiple possibilities when your target is "à" -> the single-glyph code-point, or the combining-character points... and that's not taking into consideration whether you should consider a & à & (a+diacritic) to be the same or unique entities -- and casing is another combinatorial factor. It would be a big mistake to assume character = code-point when dealing with Unicode. > An UTF-16 string is an array of Wide_Wide_Character and an array of Wide_String. UTF-16 is perhaps the worst possible encoding you can have for Unicode. With UTF-8 you don't need to worry about byte-order (everything's sequential) and with UTF-32 you don't need to decode the information (each element *IS* a code-point)... but UTF-16 offers neither of these. ------------------------------------------------------ I guess what I'm trying to say is that if we did it right, we could modify/expand the type-system so that something like UNIVERSAL_INTEGER could be made/explicitly-specified. (And if done extremely well, something like UNIVERSAL_STRING where perhaps the only thing differentiating the strings would be the 'instantiation' with their proper character-type* and manipulation-functions.) -- GNAT already has the 'Universal_Literal_String which works in either of the following lines: Ada.Wide_Wide_Text_IO.Put_Line( Ada.Numerics.Pi'Universal_Literal_String ) Ada.Text_IO.Put_Line( Ada.Numerics.Pi'Universal_Literal_String ) In any case; I think it worth considering not just outward/downward expansion of the language, but inward/upward [unification] as well. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-16 16:55 ` Shark8 @ 2013-03-16 17:36 ` Dmitry A. Kazakov 2013-03-16 21:51 ` Shark8 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-16 17:36 UTC (permalink / raw) On Sat, 16 Mar 2013 09:55:53 -0700 (PDT), Shark8 wrote: > On Saturday, March 16, 2013 1:41:27 AM UTC-6, Dmitry A. Kazakov wrote: >> >> Thus either subtypes will have same representation or you >> won't have a class. > > I'm thinking of it more in the terms of generic operations: independent of > representation. Generics are useless for strings [and almost anything else]. Without class-wide objects you need a set of instances for each combination of encoding/character/index. No better than present mess. >> Another problem is that string types must have more >> than one interface to deal with UTF-8 etc. An UTF-8 string is *both* an >> array of Wide_Wide_Character (= Unicode code points) and an array or >> sequence of Character (octets). > > Ah, things get tricky here; Unicode is kind of a bear when you consider > 'characters' because its codepoints aren't necessarily characters. Yes, code points are glyphs. > An > example would be the so-called "combining characters" which you can use > for things like accents or ZALGO-text. (See these, respectively: > http://en.wikipedia.org/wiki/Combining_character and, http://eeemo.net/ ) It is important for rendering only, if anybody uses it. > It would be a big mistake to assume character = code-point when dealing > with Unicode. [...] Rules according to which two texts are considered equivalent can be infinitely complex. You cannot do that on the basis of per character comparison. Character = glyph = code point is good enough for most applications. > I guess what I'm trying to say is that if we did it right, we could > modify/expand the type-system so that something like UNIVERSAL_INTEGER > could be made/explicitly-specified. Arrays must have interfaces. Array interface should vary along the index and element "axes" forming a class. Any type should have a class. It should be possible to drop implementation upon inheritance composing operations with type conversion. That is basically all. It would be fully backward compatible. Actual problems lie elsewhere [MD, parallel type hierarchies]. > In any case; I think it worth considering not just outward/downward > expansion of the language, but inward/upward [unification] as well. Welcome in the club. But in order to be able to weight proposals you need a more or less formal framework to describe language type system. Already this little faces a fierce opposition. So don't expect much. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-16 17:36 ` Dmitry A. Kazakov @ 2013-03-16 21:51 ` Shark8 2013-03-17 9:36 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Shark8 @ 2013-03-16 21:51 UTC (permalink / raw) Cc: mailbox On Saturday, March 16, 2013 11:36:57 AM UTC-6, Dmitry A. Kazakov wrote: > On Sat, 16 Mar 2013 09:55:53 -0700 (PDT), Shark8 wrote: > > > On Saturday, March 16, 2013 1:41:27 AM UTC-6, Dmitry A. Kazakov wrote: > >> > >> Thus either subtypes will have same representation or you > >> won't have a class. > > > > > I'm thinking of it more in the terms of generic operations: independent of > > representation. > > Generics are useless for strings [and almost anything else]. I would disagree with that -- generics are quite useful; in the year that I was professionally programming PHP I found myself *constantly* wishing for generics (and packages, and [to a lesser extent] real records). I think it's rather a shame that the compile-time computation aspect of generics is not emphasized a bit more -- I've got an idea for exploiting this property for planetary-orbit simulation. -- but then there are a *LOT* of things in Ada that don't get enough emphasis. (A language-level time type [& duration] is such that it obliterates an entire 'section' of Jon Skeet's talk http://vimeo.com/7403673 on common programming errors/difficulties.) > Without class-wide objects you need a set of instances for each combination of > encoding/character/index. No better than present mess. I think it's not impossible to unify at least some of that -- Index, for example, is always Positive. -- I don't disagree that stings are a difficult subject, but that doesn't mean that there aren't some elegant solutions that might be applied to the problem. {Encoding might not be that difficult, we already have the character-map construct, we might be able to have an "encoding-map" which would allow us to translate freely between different encodings.} > >> Another problem is that string types must have more > >> than one interface to deal with UTF-8 etc. An UTF-8 string is *both* an > >> array of Wide_Wide_Character (= Unicode code points) and an array or > >> sequence of Character (octets). That might be less of a problem than you might think; the 'Read and 'Write should handle the Octet-view while the type as-defined handles the Array-of-[[Wide_]Wide_]Character view. > > Ah, things get tricky here; Unicode is kind of a bear when you consider > > 'characters' because its codepoints aren't necessarily characters. > > Yes, code points are glyphs. Not all -- Unicode, bing backward-compatible w/ ASCII must have control-characters, which contradict that statement. But even disregarding those, there are characters such as the "zero-width non-joiner". (see http://msmvps.com/blogs/jon_skeet/archive/2009/11/02/omg-ponies-aka-humanity-epic-fail.aspx ) > > An > > example would be the so-called "combining characters" which you can use > > for things like accents or ZALGO-text. (See these, respectively: > > > http://en.wikipedia.org/wiki/Combining_character and, http://eeemo.net/ ) > > It is important for rendering only, if anybody uses it. Nope, see above for the zero-width non-joiner. > > It would be a big mistake to assume character = code-point when dealing > > with Unicode. > [...] > > Rules according to which two texts are considered equivalent can be > infinitely complex. You cannot do that on the basis of per character > comparison. Character = glyph = code point is good enough for most > applications. > > I guess what I'm trying to say is that if we did it right, we could > > modify/expand the type-system so that something like UNIVERSAL_INTEGER > > could be made/explicitly-specified. > > Arrays must have interfaces. Array interface should vary along the index > and element "axes" forming a class. Any type should have a class. It should > be possible to drop implementation upon inheritance composing operations > with type conversion. That is basically all. It would be fully backward > compatible. Actual problems lie elsewhere [MD, parallel type hierarchies]. Parallel type hierarchies are probably the way address GUI -- you could have one for the graphical side and one for the data-side -- but I'm fairly impressed with the way Delphi handled it with the VCL. {Yes there are some warts, but that system works very well in-practice; indeed the C#/.NET components/events is a near-direct plagiarism [though w/ worse event-names, IMO]}. > > In any case; I think it worth considering not just outward/downward > > expansion of the language, but inward/upward [unification] as well. > > Welcome in the club. But in order to be able to weight proposals you need a > more or less formal framework to describe language type system. Already > this little faces a fierce opposition. So don't expect much. This is likely to be true -- but I think the reward for doing so would outweigh the costs. {Especially if we could unify strings s.t. the [[Wide_]Wide_]Character packages are merely 'instantiations' of an "abstract string."} ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-16 21:51 ` Shark8 @ 2013-03-17 9:36 ` Dmitry A. Kazakov 2013-03-18 23:13 ` Randy Brukardt 2013-03-19 0:38 ` Shark8 0 siblings, 2 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-17 9:36 UTC (permalink / raw) On Sat, 16 Mar 2013 14:51:58 -0700 (PDT), Shark8 wrote: > I think it's rather a shame that the compile-time computation aspect of > generics is not emphasized a bit more You need no generics in order to compute something statically. Yes Ada could be much better with an ability to declare a function static or conditionally static. >> Without class-wide objects you need a set of instances for each combination of >> encoding/character/index. No better than present mess. > > I think it's not impossible to unify at least some of that -- Index, for > example, is always Positive. -- I don't disagree that stings are a > difficult subject, but that doesn't mean that there aren't some elegant > solutions that might be applied to the problem. I commented on a generic solution which would necessarily preserve the status quo that string types are unrelated. This is the key point. In order to reduce complexity we need operations like Put_Line become either class-wide or primitive [both operate on whole class]. >> >> Another problem is that string types must have more >>>> than one interface to deal with UTF-8 etc. An UTF-8 string is *both* an >>>> array of Wide_Wide_Character (= Unicode code points) and an array or >>>> sequence of Character (octets). > > That might be less of a problem than you might think; the 'Read and 'Write > should handle the Octet-view while the type as-defined handles the > Array-of-[[Wide_]Wide_]Character view. That would make string tagged, which in turn would imply certain representation [embedded tag] and forced by-reference semantics. The consequences are far reaching, e.g. you would have to drop slices etc. My wish is to allow T'Class constructed for an untagged type by adding a tag. E.g. T and T'Class would have different representations. This is again a key issue. Ada often conflates interface and representation/implementation. This must be fixed. But I am not even allowed to name subtype Positive is Integer range 1..Integer'Last; a type. What would happed if I asked to be able to provide an alternative representation for Positive? To disallow unary minus? >>> In any case; I think it worth considering not just outward/downward >>> expansion of the language, but inward/upward [unification] as well. >> >> Welcome in the club. But in order to be able to weight proposals you need a >> more or less formal framework to describe language type system. Already >> this little faces a fierce opposition. So don't expect much. > > This is likely to be true -- but I think the reward for doing so would > outweigh the costs. {Especially if we could unify strings s.t. the > [[Wide_]Wide_]Character packages are merely 'instantiations' of an > "abstract string."} It is not only strings. There are other types which are presently unrelated though share various interfaces [Ordered, Copyable, Comparable, Additive, Multiplicative, Indexed, Record etc]. The language does not allow to specify interfaces and have class-wide instances of those. I presume that back in 90's there was too much opposition to overhaul the type system. Tagged types were added to the existing types, while one should have made classes and interfaces fundamental to all types. We got an outbuilding instead of new fundament. [We must be happy that Taft managed to pressure for at least this change.] -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-17 9:36 ` Dmitry A. Kazakov @ 2013-03-18 23:13 ` Randy Brukardt 2013-03-19 9:12 ` Dmitry A. Kazakov 2013-03-19 0:38 ` Shark8 1 sibling, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-03-18 23:13 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:1hvv2kd9smnfx.6spgz9thd1mh$.dlg@40tude.net... ... >> That might be less of a problem than you might think; the 'Read and >> 'Write >> should handle the Octet-view while the type as-defined handles the >> Array-of-[[Wide_]Wide_]Character view. > >That would make string tagged, which in turn would imply certain >representation [embedded tag] and forced by-reference semantics. The >consequences are far reaching, e.g. you would have to drop slices etc. For string, requiring by-reference would have little practical effect, as almost all compilers pass strings by-reference anyway. There is no OOP-way to make slicing work, since slices are by definition references (in C-terms, they're an l-value), and since the representations have to vary, that isn't going to be possible. My rough proposed Root_String_Type would be an abstract tagged type, but it wouldn't provide slices directly (it would provide functions for that purpose). But that's OK, because such a construct would have to be alongside the existing string types; we can't replace or change them in any significant way and I think that means we'll have to start over. ... > This is again a key issue. Ada often conflates interface and > representation/implementation. This must be fixed. But I am not even > allowed to name > > subtype Positive is Integer range 1..Integer'Last; > > a type. What would happed if I asked to be able to provide an alternative > representation for Positive? To disallow unary minus? That's easy: nothing would happen. Compatibility with existing code almost always has priority. If you can describe the changes in terms of the existing semantics, then you might have a chance, but if you invent your own terminology and propose to throw out the existing rules, no one is going to pay much attention. Even if you are right (and you may very well be right), it is just too likely to introduce intolerable incompatibilities. ... > I presume that back in 90's there was too much opposition to overhaul the > type system. Tagged types were added to the existing types, while one > should have made classes and interfaces fundamental to all types. We got > an > outbuilding instead of new fundament. [We must be happy that Taft managed > to pressure for at least this change.] You do know that the original Ada 9x design was much like you are describing, with 'Class for all types? 'Class for untagged types eventually got dropped because of various semantics issues (mainly, they just worked differently than the tagged version, and that was thought to be confusing) -- and when people thought that Ada 9x was just too large and stuff had to go, that was one of the first. Of course, for composite types, almost everything should be tagged and controlled (there would have to be a critical memory usage reason to avoid that), and in that case everything works sanely. (Even indexing, given the new Ada 2012 features). So we're mostly talking about scalar type 'Class (we don't need any more anonymous access types of any kind, and they're essentially structural equivalence as it is, so 'Class would buy very little there). I think the more interesting thing is that we've never brought it back. It seems that we haven't seen any truly compelling uses for the idea, because if we had, I'm sure it would have come back in Ada 2005 or Ada 2012. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-18 23:13 ` Randy Brukardt @ 2013-03-19 9:12 ` Dmitry A. Kazakov 2013-03-19 21:19 ` Randy Brukardt 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-19 9:12 UTC (permalink / raw) On Mon, 18 Mar 2013 18:13:39 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:1hvv2kd9smnfx.6spgz9thd1mh$.dlg@40tude.net... > ... >>> That might be less of a problem than you might think; the 'Read and 'Write >>> should handle the Octet-view while the type as-defined handles the >>> Array-of-[[Wide_]Wide_]Character view. >> >>That would make string tagged, which in turn would imply certain >>representation [embedded tag] and forced by-reference semantics. The >>consequences are far reaching, e.g. you would have to drop slices etc. > > For string, requiring by-reference would have little practical effect, as > almost all compilers pass strings by-reference anyway. There is no OOP-way > to make slicing work, since slices are by definition references (in C-terms, > they're an l-value), and since the representations have to vary, that isn't > going to be possible. It is well possible. Consider tag a constraint as array bounds are. Allow constraints (=discriminants) passed independently as compilers already do for array bounds. This gives you array interfaces while keeping arrays as they are, plain arrays. > My rough proposed Root_String_Type would be an abstract tagged type, I definitely don't want strings tagged. > but it > wouldn't provide slices directly (it would provide functions for that > purpose). But that's OK, because such a construct would have to be alongside > the existing string types; we can't replace or change them in any > significant way and I think that means we'll have to start over. But we can. The point is that the existing type system of Ada is fully compatible with the system I am talking about. There is no compatibility issues. > So we're mostly talking about scalar type 'Class (we > don't need any more anonymous access types of any kind, and they're > essentially structural equivalence as it is, so 'Class would buy very little > there). No, this is a huge difference. Especially for scalar types we need clear interfaces because otherwise programs get infested by a combinatorial explosion of generic instances. Presently, I am unable to compile my project under any 32-bit system because GNAT compiler needs 3GB an more to instantiate all generics, apart from that this takes 3-4 hours on an i7, and the project has hundreds of meaningless packages which only purpose is to instantiate. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-19 9:12 ` Dmitry A. Kazakov @ 2013-03-19 21:19 ` Randy Brukardt 2013-03-20 11:21 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-03-19 21:19 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:vo941i7imo8t$.1jjjox9r1hkqa.dlg@40tude.net... > On Mon, 18 Mar 2013 18:13:39 -0500, Randy Brukardt wrote: > >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >> news:1hvv2kd9smnfx.6spgz9thd1mh$.dlg@40tude.net... >> ... >>>> That might be less of a problem than you might think; the 'Read and >>>> 'Write >>>> should handle the Octet-view while the type as-defined handles the >>>> Array-of-[[Wide_]Wide_]Character view. >>> >>>That would make string tagged, which in turn would imply certain >>>representation [embedded tag] and forced by-reference semantics. The >>>consequences are far reaching, e.g. you would have to drop slices etc. >> >> For string, requiring by-reference would have little practical effect, as >> almost all compilers pass strings by-reference anyway. There is no >> OOP-way >> to make slicing work, since slices are by definition references (in >> C-terms, >> they're an l-value), and since the representations have to vary, that >> isn't >> going to be possible. > > It is well possible. Consider tag a constraint as array bounds are. Allow > constraints (=discriminants) passed independently as compilers already do > for array bounds. This gives you array interfaces while keeping arrays as > they are, plain arrays. No, it's not possible. In order to solve the string problem, we have to decouple the representation and the interface. But for slices, you have to know the representation in order to be able to pass it meaningfully. Moreover, the representation is not necessarily an array (UTF-8 encoding is not a normal array if you are using the character interface). So by-reference passing of part of something that is not necessarily a contiguous array is not possible. (In addition, such an interface ought to support chunked representations and the like, and again that cannot pass just a part.) >> My rough proposed Root_String_Type would be an abstract tagged type, > > I definitely don't want strings tagged. Then forget it. All composite types ought to be tagged; the root of the existing problem is that arrays aren't tagged. >> but it >> wouldn't provide slices directly (it would provide functions for that >> purpose). But that's OK, because such a construct would have to be >> alongside >> the existing string types; we can't replace or change them in any >> significant way and I think that means we'll have to start over. > > But we can. The point is that the existing type system of Ada is fully > compatible with the system I am talking about. There is no compatibility > issues. You're dreaming - it's not possible. As soon as you change the inheritance rules (which you have to do), you'll break the semantics of derived types (they'll inherit different operations). The only alternative to that is to invent a totally new kind of type declaration that pretty similar to derived types -- and that will never fly as it would be too confusing to users. >> So we're mostly talking about scalar type 'Class (we >> don't need any more anonymous access types of any kind, and they're >> essentially structural equivalence as it is, so 'Class would buy very >> little >> there). > > No, this is a huge difference. Especially for scalar types we need clear > interfaces because otherwise programs get infested by a combinatorial > explosion of generic instances. I don't follow. I said we need 'Class for scalar types (but not access types), and you said no, we need 'Class for scalar types. I don't think we need 'Class for access types, because the effect is essentially the same as what we already have for anonymous access types (the only real change needed would be to give those kinds of access types an optional name). I could imagine some disagreement on this latter point, but not on the first one. > Presently, I am unable to compile my project under any 32-bit system > because GNAT compiler needs 3GB an more to instantiate all generics, apart > from that this takes 3-4 hours on an i7, and the project has hundreds of > meaningless packages which only purpose is to instantiate. For someone that hates generics, why would you have so many? My programs are almost generic-free, most of the ones I have are one-offs like iterators and binary data readers (like Sequential_IO). The few times I've goine further, I've regretted it. Maybe you're trying too hard to be Object-Oriented; I find that is almost never worth the effort -- just build a good ADT and make it tagged and controlled so that the next person can extend it if they have to. (But hopefully they won't have to.) Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-19 21:19 ` Randy Brukardt @ 2013-03-20 11:21 ` Dmitry A. Kazakov 2013-03-20 23:57 ` Randy Brukardt 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-20 11:21 UTC (permalink / raw) On Tue, 19 Mar 2013 16:19:54 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:vo941i7imo8t$.1jjjox9r1hkqa.dlg@40tude.net... >> It is well possible. Consider tag a constraint as array bounds are. Allow >> constraints (=discriminants) passed independently as compilers already do >> for array bounds. This gives you array interfaces while keeping arrays as >> they are, plain arrays. > > No, it's not possible. In order to solve the string problem, we have to > decouple the representation and the interface. But for slices, you have to > know the representation in order to be able to pass it meaningfully. You pass dope and reference. > Moreover, the representation is not necessarily an array (UTF-8 encoding is > not a normal array if you are using the character interface). In the dope you have type tag to handle class-wide instances. You will dispatch to the body which implements indexing for UTF-8 encoded arrays of characters. >>> My rough proposed Root_String_Type would be an abstract tagged type, >> >> I definitely don't want strings tagged. > > Then forget it. All composite types ought to be tagged; the root of the > existing problem is that arrays aren't tagged. If you use "tagged" in RM sense as a class of types which a tag embedded into the representation, then no. That is not the problem and I don't want arrays to have tag. I want array interfaces and an ability to have objects of the type A'Class where A is an array type. The representation of A'Class will have tag. The representation of A will not. >>> but it >>> wouldn't provide slices directly (it would provide functions for that >>> purpose). But that's OK, because such a construct would have to be >>> alongside >>> the existing string types; we can't replace or change them in any >>> significant way and I think that means we'll have to start over. >> >> But we can. The point is that the existing type system of Ada is fully >> compatible with the system I am talking about. There is no compatibility >> issues. > > You're dreaming - it's not possible. As soon as you change the inheritance > rules (which you have to do), you'll break the semantics of derived types > (they'll inherit different operations). I won't change these rules. Remember, in my model they already inherit, they will keep on doing that, just explicitly rather than implicitly like now. > I don't think we > need 'Class for access types, You need them because access types shall implement "access interface." We need access interface for user-defined referential types. > because the effect is essentially the same as > what we already have for anonymous access types I don't see why. I want to be able to declare my own type as an access type: type Handle is private access T; private type Handle is record Connection : DB_Connection_Handle; Table : Unbounded_String; ... -- etc end record; with the semantics of new, Free, dereferencing defined as I wish. And I want to be able to write a class-wide subprogram which would take both Handle and some plain access type as a parameter. This is well possible in the T'Class is constructed by adding type tag. >> Presently, I am unable to compile my project under any 32-bit system >> because GNAT compiler needs 3GB an more to instantiate all generics, apart >> from that this takes 3-4 hours on an i7, and the project has hundreds of >> meaningless packages which only purpose is to instantiate. > > For someone that hates generics, why would you have so many? I have: 1. I/O modes of input, output, duplex; 2. Specific values of types: Integer_n, Unsigned_n, String, Wide_String, IEEE_Float_n; 3. Devices responsible to handle "registers" holding values; 4. Handles to registers; 5. Publishing value change events and monitors of; 6. Much whished, but practically impossible to do, bounded values. Here you are. On top of that there exist immense problems with explicit conversions which needed between, say, a handle to a duplex register, when an output one is expected. It is not just N instances it is also 2**N combinations of cross operations. > Maybe you're trying too hard to be Object-Oriented; I am trying to have it type-safe. It would be just impossible to do in Ada 95. In Ada 2005, which has Java interfaces, it gives what I described. Lack of MI, which is worked around using generics. I guess that MI would slash the amount of code by ten. MD would do another tenth. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-20 11:21 ` Dmitry A. Kazakov @ 2013-03-20 23:57 ` Randy Brukardt 2013-03-21 10:30 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-03-20 23:57 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:1raubw1sk48ca$.69rdgczvnnf.dlg@40tude.net... > On Tue, 19 Mar 2013 16:19:54 -0500, Randy Brukardt wrote: > >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >> news:vo941i7imo8t$.1jjjox9r1hkqa.dlg@40tude.net... > >>> It is well possible. Consider tag a constraint as array bounds are. >>> Allow >>> constraints (=discriminants) passed independently as compilers already >>> do >>> for array bounds. This gives you array interfaces while keeping arrays >>> as >>> they are, plain arrays. >> >> No, it's not possible. In order to solve the string problem, we have to >> decouple the representation and the interface. But for slices, you have >> to >> know the representation in order to be able to pass it meaningfully. > > You pass dope and reference. You have to know the representation of what you reference in order to access it, even after the "dope and reference". The only way to handle differing representations is to pass accessor thunks along with the dope, but that only allows you to access individual elements. Turning every slice reference into a loop of thunk calls is just way to complicated for the usage (which is pretty rare, especially if packages like Unbounded_Strings are made class-wide). >> Moreover, the representation is not necessarily an array (UTF-8 encoding >> is >> not a normal array if you are using the character interface). > > In the dope you have type tag to handle class-wide instances. You will > dispatch to the body which implements indexing for UTF-8 encoded arrays of > characters. If any dispatching is involved, the syntax ought to be that of a function call. That allows indexing but not slicing. Even if you are willing to confuse users with implicit dispatching, you're also talking about turning every slice reference into a loop. The extra complication would be intolerable for most vendors. >>>> My rough proposed Root_String_Type would be an abstract tagged type, >>> >>> I definitely don't want strings tagged. >> >> Then forget it. All composite types ought to be tagged; the root of the >> existing problem is that arrays aren't tagged. > > If you use "tagged" in RM sense as a class of types which a tag embedded > into the representation, then no. That is not the problem and I don't want > arrays to have tag. I want array interfaces and an ability to have objects > of the type A'Class where A is an array type. The representation of > A'Class > will have tag. The representation of A will not. Why do you care? String objects are a lot bigger than a tag, so it can't be a memory usage concern. The only other place it could possibly matter is I/O. But for package like Text_IO, a tag and dispatching is exactly what you want, and for 98% of strings, that's what they ultimately get used for. For streaming and the like, the representation does not include the tag if you stream a specific type. So what's the problem?? Removing a tag from an object is an optimization; I believe every object should have a tag and it's up to the compiler how to implement it. It's really none of your (the programmer's) business (in the absence of representation clauses). ... >> I don't think we >> need 'Class for access types, > > You need them because access types shall implement "access interface." We > need access interface for user-defined referential types. Ada 2012 has user-defined referential types. You can do everything you need with plain-old tagged types. >> because the effect is essentially the same as >> what we already have for anonymous access types > > I don't see why. I want to be able to declare my own type as an access > type: > > type Handle is private access T; > private > type Handle is record > Connection : DB_Connection_Handle; > Table : Unbounded_String; > ... -- etc > end record; > > with the semantics of new, Free, dereferencing defined as I wish. You can do the latter two in Ada 2012 as it stands; the first can easily be simulated with a constructor function. (Oh, that's right, you can't stand constructor functions.) But in any case, this is a bad idea. You don't want to explicitly handle memory management in modern programs. Do it under the covers somewhere (like in the containers packages); do *not* expose access types. > And I > want to be able to write a class-wide subprogram which would take both > Handle and some plain access type as a parameter. As I said, no new code should be exposing raw access types. Something like the container Cursor type is a much better way to handle the need for referential semantics. ... >> For someone that hates generics, why would you have so many? > > I have: > > 1. I/O modes of input, output, duplex; Seems like a runtime parameter, not a compile-time one. (i.e. Mode in the I/O packages). > 2. Specific values of types: Integer_n, Unsigned_n, String, Wide_String, > IEEE_Float_n; Yes, of course, this is the problem that requires generics, mainly building things like the Ada containers. > 3. Devices responsible to handle "registers" holding values; I don't see how a generic would help here. It is illegal to have most representation clauses in a generic body, so I don't see how you could even have a generic in this case. (It certainly wouldn't work in Janus/Ada, can't talk about GNAT.) > 4. Handles to registers; Pretty much the same as the previous. The package involved would be so small and there would be so few of them (one for each kind of native register type) that I'd just copy the text and do a block substitution to make a new one. Generics would just get in the way (and add overhead on a compiler that does sharing, like Janus/Ada). > 5. Publishing value change events and monitors of; Maybe, if you need them to work on multiple types. Seems like a sort of container, to me. > 6. Much whished, but practically impossible to do, bounded values. Seems like that fits under #2 (it's not possible to do these without knowing the underlying representation, unless you're willing to make them very expensive with tons of barely necessary exception handlers). Here again, I'd make a package for each such type that I needed. (That's precisely how this issue is handled in the Janus/Ada compiler -- no generics in sight.) > Here you are. On top of that there exist immense problems with explicit > conversions which needed between, say, a handle to a duplex register, when > an output one is expected. It is not just N instances it is also 2**N > combinations of cross operations. Again, I don't see any good reason to try to separate these things. >> Maybe you're trying too hard to be Object-Oriented; > > I am trying to have it type-safe. It would be just impossible to do in Ada > 95. In Ada 2005, which has Java interfaces, it gives what I described. > Lack > of MI, which is worked around using generics. I guess that MI would slash > the amount of code by ten. MD would do another tenth. It's not worth it to be type-safe in this way. Especially as preconditions/postconditions combined with static analysis give the same effect (compile time checking) with 10% of the work. There definitely is such a thing as being too type-safe. Of course, YMMV. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-20 23:57 ` Randy Brukardt @ 2013-03-21 10:30 ` Dmitry A. Kazakov 2013-03-21 23:27 ` Randy Brukardt 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-21 10:30 UTC (permalink / raw) On Wed, 20 Mar 2013 18:57:58 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:1raubw1sk48ca$.69rdgczvnnf.dlg@40tude.net... >> On Tue, 19 Mar 2013 16:19:54 -0500, Randy Brukardt wrote: >> >>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >>> news:vo941i7imo8t$.1jjjox9r1hkqa.dlg@40tude.net... >> >>>> It is well possible. Consider tag a constraint as array bounds are. Allow >>>> constraints (=discriminants) passed independently as compilers already >>>> do for array bounds. This gives you array interfaces while keeping arrays >>>> as they are, plain arrays. >>> >>> No, it's not possible. In order to solve the string problem, we have to >>> decouple the representation and the interface. But for slices, you have >>> to know the representation in order to be able to pass it meaningfully. >> >> You pass dope and reference. > > You have to know the representation of what you reference in order to access > it, even after the "dope and reference". Why? So long the dope contains the type tag, the string object is class-wide. For a class-wide object I should not care about representations. Representations to be handled after ultimate dispatch happens. The specific body will know the representation statically. >>> Moreover, the representation is not necessarily an array (UTF-8 encoding is >>> not a normal array if you are using the character interface). >> >> In the dope you have type tag to handle class-wide instances. You will >> dispatch to the body which implements indexing for UTF-8 encoded arrays of >> characters. > > If any dispatching is involved, the syntax ought to be that of a function > call. That allows indexing but not slicing. Depends on whether slicing to produce a class-wide slice object or a specific type object. I cannot tell what would be better, but in both cases slicing should be a proper operation (two operations, actually, for l- and r-values). > Even if you are willing to confuse users with implicit dispatching, you're > also talking about turning every slice reference into a loop. I don't see why. When the slice object happens to be class-wide, you have a dope with a tag, bounds and a reference to some yet-to-be-discovered representation. When the slice is specific, you have a dope with bounds and a reference to some statically known representation. >>>>> My rough proposed Root_String_Type would be an abstract tagged type, >>>> >>>> I definitely don't want strings tagged. >>> >>> Then forget it. All composite types ought to be tagged; the root of the >>> existing problem is that arrays aren't tagged. >> >> If you use "tagged" in RM sense as a class of types which a tag embedded >> into the representation, then no. That is not the problem and I don't want >> arrays to have tag. I want array interfaces and an ability to have objects >> of the type A'Class where A is an array type. The representation of >> A'Class will have tag. The representation of A will not. > > Why do you care? String objects are a lot bigger than a tag, so it can't be > a memory usage concern. The only other place it could possibly matter is > I/O. But for package like Text_IO, a tag and dispatching is exactly what you > want, and for 98% of strings, that's what they ultimately get used for. For > streaming and the like, the representation does not include the tag if you > stream a specific type. So what's the problem?? The problem is slicing and interfacing to other languages. Tagged string will require copying in and/or out each time you pass a slice to a subprogram. On top of that tagged types are by-reference which contradicts to copying. > Removing a tag from an object is an optimization; I believe every object > should have a tag and it's up to the compiler how to implement it. It's > really none of your (the programmer's) business (in the absence of > representation clauses). Only class-wide objects, you mean. Specific object need no tags and those with representation aspects shall not have it. As for considering it optimization, I really want this rather in the contract. Because the mechanism of adding some information to a class-wide object looks very promising beyond tags. We could use it on so many other cases: 1. Dimensioned values 2. Array bounds 3. Matrix dimensions 4. Storage pool reference in a pointer object ... >>> I don't think we >>> need 'Class for access types, >> >> You need them because access types shall implement "access interface." We >> need access interface for user-defined referential types. > > Ada 2012 has user-defined referential types. You can do everything you need > with plain-old tagged types. Like having it 16-bit long? I don't like when the language mandates representation of use-defined types. It looks more like a discount center. > But in any case, this is a bad idea. You don't want to explicitly handle > memory management in modern programs. Do it under the covers somewhere (like > in the containers packages); do *not* expose access types. Container libraries need to be implemented as well. I don't want to expose access type, I want referential semantics. >> And I >> want to be able to write a class-wide subprogram which would take both >> Handle and some plain access type as a parameter. > > As I said, no new code should be exposing raw access types. Something like > the container Cursor type is a much better way to handle the need for > referential semantics. But 4.1.5 does not hide access types. On the contrary it mandates access type as the discriminant. > ... >>> For someone that hates generics, why would you have so many? >> >> I have: >> >> 1. I/O modes of input, output, duplex; > > Seems like a runtime parameter, not a compile-time one. (i.e. Mode in the > I/O packages). No, it is intended for static checks. E.g. you cannot apply certain operations to an input object. >> 2. Specific values of types: Integer_n, Unsigned_n, String, Wide_String, >> IEEE_Float_n; > > Yes, of course, this is the problem that requires generics, mainly building > things like the Ada containers. > >> 3. Devices responsible to handle "registers" holding values; > > I don't see how a generic would help here. Each device instantiates its own register object types. The pattern looks like generic type Base_Type is new ... -- Some device specific base package Generic_Input_Scalar_Dimensioned_Whatever is type Device_Register_Type is new Base_Type and Input_Interface and Scalar_Interface ... with private; It is only needed because there is no MI. It also introduces some run-time overhead as it is turned upside down. Actually the device-specific stuff should have been added to some type/mode specific implementation. But that is a minor nuisance comparing to geometric explosion of packages and their instances. >> 4. Handles to registers; > > Pretty much the same as the previous. The package involved would be so small > and there would be so few of them (one for each kind of native register > type) that I'd just copy the text and do a block substitution to make a new > one. Generics would just get in the way (and add overhead on a compiler that > does sharing, like Janus/Ada). It is not so small, because it has to implement a number of operations. The problem is that there are hundreds of such generic packages containing meaningless cut-and-paste code like function Get_Name (Register : Register_Handle) return String is begin return Register.Ptr.Get_Name; end Get_Name; >> 5. Publishing value change events and monitors of; > > Maybe, if you need them to work on multiple types. Seems like a sort of > container, to me. But, again, more than one. It a multiplicator. For an input Integer_16 handle I need a monitor object which spits an Integer_16 values. Once a single generic comes inside it explodes like a particle in the collider. >> 6. Much whished, but practically impossible to do, bounded values. > > Seems like that fits under #2 (it's not possible to do these without knowing > the underlying representation, unless you're willing to make them very > expensive with tons of barely necessary exception handlers). Here again, I'd > make a package for each such type that I needed. (That's precisely how this > issue is handled in the Janus/Ada compiler -- no generics in sight.) I cannot write so many packages manually. It will be many thousands. Generics offer at least some help with code reuse. > > Here you are. On top of that there exist immense problems with explicit >> conversions which needed between, say, a handle to a duplex register, when >> an output one is expected. It is not just N instances it is also 2**N >> combinations of cross operations. > > Again, I don't see any good reason to try to separate these things. For type safety. I want that a program that tries to send a string value to a digital analogue input would not compile rather than fail at run-time [which could be extremely expensive]. It turned much harder than I thought it initially. >>> Maybe you're trying too hard to be Object-Oriented; >> >> I am trying to have it type-safe. It would be just impossible to do in Ada >> 95. In Ada 2005, which has Java interfaces, it gives what I described. Lack >> of MI, which is worked around using generics. I guess that MI would slash >> the amount of code by ten. MD would do another tenth. > > It's not worth it to be type-safe in this way. Especially as > preconditions/postconditions combined with static analysis give the same > effect (compile time checking) with 10% of the work. Even if it were compile-time it would require same representation for all involved objects. How would I do it for Unsigned_1 and String? -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-21 10:30 ` Dmitry A. Kazakov @ 2013-03-21 23:27 ` Randy Brukardt 2013-03-22 16:07 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-03-21 23:27 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:i93qv6ba3bv0.wuicbsmfm5ha.dlg@40tude.net... > On Wed, 20 Mar 2013 18:57:58 -0500, Randy Brukardt wrote: ... >> Even if you are willing to confuse users with implicit dispatching, >> you're >> also talking about turning every slice reference into a loop. > > I don't see why. When the slice object happens to be class-wide, you have > a > dope with a tag, bounds and a reference to some yet-to-be-discovered > representation. When the slice is specific, you have a dope with bounds > and > a reference to some statically known representation. The underlying model of a slice is an implicit loop. We already have to use loops to implement some slices in existing Ada; there is no possibility of eliminating that. That's because ultimately everything is done on machine objects (bytes, words, dwords, etc.) and you always need a loop if you are going to operate on more than one. Of course, if you know the representation, you can get away with special-case loops (like a block move), but if you don't know the representation of the elements (or how the indexing works), a loop is the only possible implementation. Because of that, there is almost no value to slicing operations unless you know the representation and can use block move instructions. Otherwise, you are setting up a loop of dispatching operations, one element at a time. It's dubious that this is worth special language support. There's nothing that you can do with a slice that you can't do with a loop, and usually the loop is easier to write and understand. The only advantage of the slice is the optimized code that it can produce, and that's gone if you don't have the representation. (The whole idea of slices was a mistake that probably shouldn't have been in the language in the first place -- it caused a reliance on not very good string processing instead of providing a reasonable mechanism from the beginning.) ... >> Why do you care? String objects are a lot bigger than a tag, so it can't >> be >> a memory usage concern. The only other place it could possibly matter is >> I/O. But for package like Text_IO, a tag and dispatching is exactly what >> you >> want, and for 98% of strings, that's what they ultimately get used for. >> For >> streaming and the like, the representation does not include the tag if >> you >> stream a specific type. So what's the problem?? > > The problem is slicing and interfacing to other languages. Tagged string > will require copying in and/or out each time you pass a slice to a > subprogram. On top of that tagged types are by-reference which contradicts > to copying. Slicing is already impossible for the case that we're talking about, and interface to foreign language already has to be done through special types. (Using a type that doesn't have convention C is wrong for C interfacing, although your current compiler might allow it, there is no reason to assume another has the same rules.) Clearly, types with an appropriate representation clause need to follow that clause (or be rejected), but again I ask why do you care how types that are going to be used purely by Ada (and that had better be most of them) are implemented?? >> Removing a tag from an object is an optimization; I believe every object >> should have a tag and it's up to the compiler how to implement it. It's >> really none of your (the programmer's) business (in the absence of >> representation clauses). > > Only class-wide objects, you mean. Specific object need no tags and those > with representation aspects shall not have it. No I mean all objects. It should be none of your business how the compiler implements objects -- any objects -- you ought to want the compiler to do the best job it can, not put arbitrary and possibly counter-productive restrictions on it. If you need a particular representation, then you need to give a representation clause. Otherwise, leave the compiler alone. > As for considering it optimization, I really want this rather in the > contract. Because the mechanism of adding some information to a class-wide > object looks very promising beyond tags. We could use it on so many other > cases: > > 1. Dimensioned values > 2. Array bounds > 3. Matrix dimensions > 4. Storage pool reference in a pointer object > ... None of the above makes any sense whatsoever. We need all of those things in the object in order to generate code. (Janus/Ada uses a single representation for all objects of a type, and you don't have enough money to change that.) It's possible in limited circumstances to avoid that (statically constrained arrays come to mind), but every such special case greatly increases the complication of a compiler. I suspect that if your model became the law of the land, compilers would generate very bad code for any cases like the ones you want, and you wouldn't be able to use the result anyway. And again, I don't think you have enough money to change that situation (maybe if I won the Powerball I could...) >>>> I don't think we >>>> need 'Class for access types, >>> >>> You need them because access types shall implement "access interface." >>> We >>> need access interface for user-defined referential types. >> >> Ada 2012 has user-defined referential types. You can do everything you >> need >> with plain-old tagged types. > > Like having it 16-bit long? I don't like when the language mandates > representation of use-defined types. It looks more like a discount center. If you *really* need a 16-bit pointer, that means you have truly critical time/space needs. And in that case, you really need to dump everything modern (OOP, interfaces, etc.) in the trash can and write basic Ada 83-style ADT code, without any attempt at anything special. Because the overheads associated with OOP (especially any form of multiple inheritance) are always going to cost many times in time and space your "16-bit pointer". A compiler could fake it, but all that you've done is moved the costs into a corner where they're less obvious. They didn't magically go away. Besides, if the sort of uses you are asking about get prominence, then clearly compiler writers will try to make their implementations more efficient (as AdaCore has done with finalization). There is not fundamental reason that a compiler writer with sufficient motivation couldn't leave the tags out of tagged objects (that was a goal for the design of Ada 9x, and I believe it is possible). There's no reason to invent new semantics when the existing semantics is good enough. >> But in any case, this is a bad idea. You don't want to explicitly handle >> memory management in modern programs. Do it under the covers somewhere >> (like >> in the containers packages); do *not* expose access types. > > Container libraries need to be implemented as well. I don't want to expose > access type, I want referential semantics. And that's the point of 4.1.5. The only thing you can't do is write "new" that way, but calling a function to do that doesn't seem that bad. >>> And I >>> want to be able to write a class-wide subprogram which would take both >>> Handle and some plain access type as a parameter. >> >> As I said, no new code should be exposing raw access types. Something >> like >> the container Cursor type is a much better way to handle the need for >> referential semantics. > > But 4.1.5 does not hide access types. On the contrary it mandates access > type as the discriminant. Ahh, but that was a case where the "existing semantics" was good enough so we didn't create a new thing. This is a very special access type, one that almost never can be copied -- for practical purposes it can only be dereferenced. That's what we needed. Note that there is no intent that anyone ever create an object for this access type (and that is where all of the problems lie). It just has the syntax of an access type so we didn't have to invent a new thing to get dereferencing. >> ... >>>> For someone that hates generics, why would you have so many? Thanks for the lengthy explanation. I'm not going to comment on it individually anymore, because one is always on thin ice talking about another's code without knowing all of the issues involved, and there seems to be a summary point. ... >>>> Maybe you're trying too hard to be Object-Oriented; >>> >>> I am trying to have it type-safe. It would be just impossible to do in >>> Ada >>> 95. In Ada 2005, which has Java interfaces, it gives what I described. >>> Lack >>> of MI, which is worked around using generics. I guess that MI would >>> slash >>> the amount of code by ten. MD would do another tenth. >> >> It's not worth it to be type-safe in this way. Especially as >> preconditions/postconditions combined with static analysis give the same >> effect (compile time checking) with 10% of the work. > > Even if it were compile-time it would require same representation for all > involved objects. How would I do it for Unsigned_1 and String? I don't see this necessarily. You certainly can use dispatching to support different representations. But I still think you are trying too hard to avoid run-time checks. I think these need a balance, especially as modern static analyzers can remove the vast majority of them (or warn that they might fail, which is a cause for concern). (This is assuming use of Pre/Post, of course.) I realize some systems have to be locked down without run-time checks because of outside reliability requirements, but these systems can't have complex systems of generics (or usually have any dispatching or memory management, either). Ada's type system isn't powerful enough to push everything to static checks, and indeed I'm dubious that any practical system could be that powerful. Giant edifices of generics and/or interfaces are essentially impossible to understand and debug (and in the margin, compile). Simplify! Simplify! I'd rather use a few run-time checks and a few run-time parameters than end up with dozens of types and packages. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-21 23:27 ` Randy Brukardt @ 2013-03-22 16:07 ` Dmitry A. Kazakov 2013-03-22 20:10 ` Shark8 2013-03-23 2:33 ` Randy Brukardt 0 siblings, 2 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-22 16:07 UTC (permalink / raw) On Thu, 21 Mar 2013 18:27:22 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:i93qv6ba3bv0.wuicbsmfm5ha.dlg@40tude.net... >> On Wed, 20 Mar 2013 18:57:58 -0500, Randy Brukardt wrote: > ... >>> Even if you are willing to confuse users with implicit dispatching, you're >>> also talking about turning every slice reference into a loop. >> I don't see why. When the slice object happens to be class-wide, you have >> a dope with a tag, bounds and a reference to some yet-to-be-discovered >> representation. When the slice is specific, you have a dope with bounds >> and a reference to some statically known representation. > > The underlying model of a slice is an implicit loop. We already have to use > loops to implement some slices in existing Ada; there is no possibility of > eliminating that. That's because ultimately everything is done on machine > objects (bytes, words, dwords, etc.) and you always need a loop if you are > going to operate on more than one. I still don't understand why is it relevant. Ada already has "loops" you are talking about for String and Wide_String. Why cannot you use them for their representations after selecting through dispatch? > Because of that, there is almost no value to slicing operations unless you > know the representation and can use block move instructions. I want to be able to pass a slice to Put_Line without copying. > There's nothing that you can do with a slice that you can't do with a loop, > and usually the loop is easier to write and understand. Are you suggesting to call Put from a loop instead of Put_Line? I Don't want the language forcing me doing that. >>> Why do you care? String objects are a lot bigger than a tag, so it can't be >>> a memory usage concern. The only other place it could possibly matter is >>> I/O. But for package like Text_IO, a tag and dispatching is exactly what you >>> want, and for 98% of strings, that's what they ultimately get used for. For >>> streaming and the like, the representation does not include the tag if you >>> stream a specific type. So what's the problem?? >> >> The problem is slicing and interfacing to other languages. Tagged string >> will require copying in and/or out each time you pass a slice to a >> subprogram. On top of that tagged types are by-reference which contradicts >> to copying. > > Slicing is already impossible for the case that we're talking about, ? Normal strings have slices and should continue to have them. > and > interface to foreign language already has to be done through special types. Which should certainly be in the same class! There is no semantic reason why char_array should not be considered string. > Clearly, types with an appropriate representation clause need to follow that > clause (or be rejected), but again I ask why do you care how types that are > going to be used purely by Ada (and that had better be most of them) are > implemented?? Because representation must be controlled by programmer, not by the language. It should be possible to declare a string object of *any* representation whatsoever. If the compiler does not know how to implement operations on this representation it should ask me, the programmer, to implement them. >>> Removing a tag from an object is an optimization; I believe every object >>> should have a tag and it's up to the compiler how to implement it. It's >>> really none of your (the programmer's) business (in the absence of >>> representation clauses). >> >> Only class-wide objects, you mean. Specific object need no tags and those >> with representation aspects shall not have it. > > No I mean all objects. It should be none of your business how the compiler > implements objects On the contrary, the compiler is free to choose a representation under the constraints specified by the programmer. I don't want Ada to become C#. >> As for considering it optimization, I really want this rather in the >> contract. Because the mechanism of adding some information to a class-wide >> object looks very promising beyond tags. We could use it on so many other >> cases: >> >> 1. Dimensioned values >> 2. Array bounds >> 3. Matrix dimensions >> 4. Storage pool reference in a pointer object >> ... > > None of the above makes any sense whatsoever. We need all of those things in > the object in order to generate code. So, you want to describe all possible problem domains in the RM? The RM should know that a matrix of 2 rows and 5 columns can be multiplied to a 5x8 matrix, but not to a 8x8 matrix? Good luck with that! > I suspect that if your model became the law of the land, compilers would > generate very bad code for any cases like the ones you want, and you > wouldn't be able to use the result anyway. Nobody tried. But I doubt it. My proposals have a goal to significantly simplify the language. Ada 2005 and 2012 added a huge number of special cases requiring special treatment. That surely complicates optimization of Ada programs which is already not great. Smaller and more regular language would be easier to optimize. >>>>> I don't think we need 'Class for access types, >>>> >>>> You need them because access types shall implement "access interface." >>>> We need access interface for user-defined referential types. >>> >>> Ada 2012 has user-defined referential types. You can do everything you >>> need with plain-old tagged types. >> >> Like having it 16-bit long? I don't like when the language mandates >> representation of use-defined types. It looks more like a discount center. > > If you *really* need a 16-bit pointer, that means you have truly critical > time/space needs. Not necessarily. It could be because the thing need to be atomic, or because I wanted to marshal it. The programmer may have his reasons. > And in that case, you really need to dump everything > modern (OOP, interfaces, etc.) in the trash can and write basic Ada 83-style > ADT code, without any attempt at anything special. Because the overheads > associated with OOP (especially any form of multiple inheritance) are always > going to cost many times in time and space your "16-bit pointer". A compiler > could fake it, but all that you've done is moved the costs into a corner > where they're less obvious. They didn't magically go away. This is a totally bogus argument. OO imposes no overhead on specific types. It does on class-wide objects, which simply non-existent in Ada 83. If you implemented class-wide objects on top of Ada 83 objects you would get exactly same overhead or more. > Besides, if the sort of uses you are asking about get prominence, then > clearly compiler writers will try to make their implementations more > efficient (as AdaCore has done with finalization). There is not fundamental > reason that a compiler writer with sufficient motivation couldn't leave the > tags out of tagged objects (that was a goal for the design of Ada 9x, and I > believe it is possible). There's no reason to invent new semantics when the > existing semantics is good enough. Nobody proposes to change tagged types. The idea is to add classes to non-tagged types by adding tag to the class-wide object while keeping specific objects as-is. >>> But in any case, this is a bad idea. You don't want to explicitly handle >>> memory management in modern programs. Do it under the covers somewhere >>> (like in the containers packages); do *not* expose access types. >> >> Container libraries need to be implemented as well. I don't want to expose >> access type, I want referential semantics. > > And that's the point of 4.1.5. The only thing you can't do is write "new" (what about 'Access? What about Unchecked_Deallocation?) > that way, but calling a function to do that doesn't seem that bad. How do I put such a reference in an array, for example? 4.1.5 would be extremely difficult to use for intended purpose. >>>> And I >>>> want to be able to write a class-wide subprogram which would take both >>>> Handle and some plain access type as a parameter. >>> >>> As I said, no new code should be exposing raw access types. Something >>> like the container Cursor type is a much better way to handle the need for >>> referential semantics. >> >> But 4.1.5 does not hide access types. On the contrary it mandates access >> type as the discriminant. > > Ahh, but that was a case where the "existing semantics" was good enough so > we didn't create a new thing. This is a very special access type, one that > almost never can be copied -- for practical purposes it can only be > dereferenced. That's what we needed. Note that there is no intent that > anyone ever create an object for this access type (and that is where all of > the problems lie). It just has the syntax of an access type so we didn't > have to invent a new thing to get dereferencing. You have a very specific use case in mind, namely containers. There is a whole world outside that, for which what you said is untrue, e.g. for smart pointers. The thing not only exposes access, it also exposes the target type. For smart pointers and handles you might what to hide both. Consider a handle to a file. You certainly don't want to make File_Descriptor it points to, visible. You want the handle to implement file I/O interface routed privately to the descriptor. You also want handles be copyiable and comparable, but treated as references to some opaque limited object. >>>>> Maybe you're trying too hard to be Object-Oriented; >>>> >>>> I am trying to have it type-safe. It would be just impossible to do in >>>> Ada 95. In Ada 2005, which has Java interfaces, it gives what I described. >>>> Lack of MI, which is worked around using generics. I guess that MI would >>>> slash the amount of code by ten. MD would do another tenth. >>> >>> It's not worth it to be type-safe in this way. Especially as >>> preconditions/postconditions combined with static analysis give the same >>> effect (compile time checking) with 10% of the work. >> >> Even if it were compile-time it would require same representation for all >> involved objects. How would I do it for Unsigned_1 and String? > > I don't see this necessarily. You certainly can use dispatching to support > different representations. No way. Consider operation Send: procedure Send (To : in out Register; Value : Unsigned_1); procedure Send (To : in out Register; Value : String); It cannot dispatch! Firstly, Unsigned_1 and String are not in the same class. Secondly, even if they were, it would be MD! So, you need MI and MD to make it happen. Without them, poor man's solution is messing with generics. > But I still think you are trying too hard to avoid run-time checks. If I weren't, I would use Perl, not Ada. I favor Ada exactly because it gives me static checks. It is sad to see Ada drifting towards run-time / dynamic-typing junk. > I think > these need a balance, especially as modern static analyzers can remove the > vast majority of them (or warn that they might fail, which is a cause for > concern). It is not about removing checks, though performance is a concern too. The major problem is that failed checks must be flagged as errors. You are a compiler writer, I am designing automation systems. To me run-time check is much too late. A fault can break real things, apart from maintenance. Imagine Claw running on an oil platform. Do you own a helicopter? -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-22 16:07 ` Dmitry A. Kazakov @ 2013-03-22 20:10 ` Shark8 2013-03-22 20:51 ` Dmitry A. Kazakov 2013-03-23 2:33 ` Randy Brukardt 1 sibling, 1 reply; 242+ messages in thread From: Shark8 @ 2013-03-22 20:10 UTC (permalink / raw) Cc: mailbox On Friday, March 22, 2013 10:07:51 AM UTC-6, Dmitry A. Kazakov wrote: > On Thu, 21 Mar 2013 18:27:22 -0500, Randy Brukardt wrote: > > > But I still think you are trying too hard to avoid run-time checks. > > If I weren't, I would use Perl, not Ada. I favor Ada exactly because it > gives me static checks. It is sad to see Ada drifting towards run-time / > dynamic-typing junk. Runtime-typing and dynamic-typing are two different things, no? (As I understand, dynamic-typing could be illustrated with PHP which plays fast and loose with items [string "5" <--> integer 5 or float 5.0], whereas run-time typing could be illustrated with Delphi and its RTTI. {The RTTI can be used to emulate dynamic-typing, even implicitly in some cases IIRC, but that is a far cry from the mashed-potatoes-typing {everything is everything else, except on error which is usually 0 and then converted to the type of 'everything' needed} of PHP}). Ada has always had run-time checking: I mean consider a type INPUTS {say for enumerating inputs from a menu-driven application of range '0'..'9'} or enumerations where we could do something like Function Prompt( items: menu ) Return INPUTS is Result: INPUT; begin -- loop -- display prompt -- get user's input string/character -- assign conversion using INPUT'Value to Result -- exit when the above conversion is valid [otherwise handle exception] -- end loop return result; end Prompt; ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-22 20:10 ` Shark8 @ 2013-03-22 20:51 ` Dmitry A. Kazakov 2013-03-22 23:34 ` Robert A Duff 2013-03-23 2:29 ` Nasser M. Abbasi 0 siblings, 2 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-22 20:51 UTC (permalink / raw) On Fri, 22 Mar 2013 13:10:18 -0700 (PDT), Shark8 wrote: > On Friday, March 22, 2013 10:07:51 AM UTC-6, Dmitry A. Kazakov wrote: >> On Thu, 21 Mar 2013 18:27:22 -0500, Randy Brukardt wrote: >> >>> But I still think you are trying too hard to avoid run-time checks. >> >> If I weren't, I would use Perl, not Ada. I favor Ada exactly because it >> gives me static checks. It is sad to see Ada drifting towards run-time / >> dynamic-typing junk. > > Runtime-typing and dynamic-typing are two different things, no? Possibly, depends on how you define it. Anyway all boils down to run-time checks (faults) vs. compile-time checks (errors/bugs). A failed run-time check is a program state to anticipate. More such checks you do, more states you have, more difficult it becomes to design tests covering these states, or just to keep in mind that such states exist and are reachable. I don't buy run-time checks unless *proven* that compile-time check would be impossible to have. And this is not an optimization issue. > Ada has always had run-time checking: Sure. [ It is trivial to put up an example where no compile-time check can exist, e.g. function Puzzle return Positive is begin if HALT (p) then return -1; else return 1; end if; end Puzzle; It is a halting problem to prove that Puzzle does not raise Constraint_Error. ] -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-22 20:51 ` Dmitry A. Kazakov @ 2013-03-22 23:34 ` Robert A Duff 2013-03-23 8:41 ` Dmitry A. Kazakov 2013-03-23 2:29 ` Nasser M. Abbasi 1 sibling, 1 reply; 242+ messages in thread From: Robert A Duff @ 2013-03-22 23:34 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > [ It is trivial to put up an example where no compile-time check can exist, > e.g. I don't think so. Compile-time checks just need to be more conservative to avoid running afoul of the halting problem. > function Puzzle return Positive is > begin > if HALT (p) then > return -1; > else > return 1; > end if; > end Puzzle; GNAT has a mode in which the above is a compile-time error. Use the -gnatwae switch, and you are using an Ada-like language in which the above is illegal. It's similar to this Ada: procedure P is Const : constant Integer := 123; begin if HALT (p) then Const := 123; -- Illegal! end if; end Puzzle; The compiler doesn't have to prove that the assignment statement is reachable, nor that the assignment will actually change the value of the constant. It's illegal anyway. The language designer gets to choose between more-conservative compile time rules versus more-liberal run-time checks. > It is a halting problem to prove that Puzzle does not raise > Constraint_Error. ] True, but your first-quoted statement above does not follow from this. In fact, it is trivial to design a language in which all language-defined errors are detected at compile time. (But it's somewhere between difficult and impossible to design a *useful* language with that property.) - Bob ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-22 23:34 ` Robert A Duff @ 2013-03-23 8:41 ` Dmitry A. Kazakov 0 siblings, 0 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-23 8:41 UTC (permalink / raw) On Fri, 22 Mar 2013 19:34:09 -0400, Robert A Duff wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > >> [ It is trivial to put up an example where no compile-time check can exist, >> e.g. > > I don't think so. Compile-time checks just need to be more conservative > to avoid running afoul of the halting problem. OK, for any written program, there is no halting problem, as you can always enumerate all states of any finite program using brute force. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-22 20:51 ` Dmitry A. Kazakov 2013-03-22 23:34 ` Robert A Duff @ 2013-03-23 2:29 ` Nasser M. Abbasi 1 sibling, 0 replies; 242+ messages in thread From: Nasser M. Abbasi @ 2013-03-23 2:29 UTC (permalink / raw) On 3/22/2013 2:51 PM, Dmitry A. Kazakov wrote: > Anyway all boils down to run-time > checks (faults) vs. compile-time checks (errors/bugs). A failed run-time > check is a program state to anticipate. More such checks you do, more > states you have, more difficult it becomes to design tests covering these > states, or just to keep in mind that such states exist and are reachable. > > I don't buy run-time checks unless *proven* that compile-time check would > be impossible to have. And this is not an optimization issue. > In languages like Matlab and others like it, which do not have static type checking and everything is done at run-time, you'll typically see more than 50% of the code just doing manual checks on function parameters to make sure it is the 'correct input' needed by the function. Since there is no compiler to check statically, what ends happening is that now the programmer is doing what the compiler could have done and much better. The programmer spends more time adding code to check that types match (is this a structure? is this a string? is this a 1D vector etc...) I am not even talking about checking that the range of the values makes sense, just to check that the input is even of the correct 'kind' that is all. All of this is such a waste of time and energy, as a strongly typed static language will not need all this, and one will simply declare variables of needed types and be done with it and then spend the time thinking on the problem domain itself and on the algorithm. The sad thing, is that more and more languages are going to this 'write anything you want and leave the checking for when the code runs' way of doing things. --Nasser ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-22 16:07 ` Dmitry A. Kazakov 2013-03-22 20:10 ` Shark8 @ 2013-03-23 2:33 ` Randy Brukardt 2013-03-23 4:44 ` Shark8 2013-03-23 9:53 ` Dmitry A. Kazakov 1 sibling, 2 replies; 242+ messages in thread From: Randy Brukardt @ 2013-03-23 2:33 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:2qwq2cdeuvhu$.qtnb8zyhuob9$.dlg@40tude.net... > On Thu, 21 Mar 2013 18:27:22 -0500, Randy Brukardt wrote: > >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >> news:i93qv6ba3bv0.wuicbsmfm5ha.dlg@40tude.net... >>> On Wed, 20 Mar 2013 18:57:58 -0500, Randy Brukardt wrote: >> ... >>>> Even if you are willing to confuse users with implicit dispatching, >>>> you're >>>> also talking about turning every slice reference into a loop. > >>> I don't see why. When the slice object happens to be class-wide, you >>> have >>> a dope with a tag, bounds and a reference to some yet-to-be-discovered >>> representation. When the slice is specific, you have a dope with bounds >>> and a reference to some statically known representation. >> >> The underlying model of a slice is an implicit loop. We already have to >> use >> loops to implement some slices in existing Ada; there is no possibility >> of >> eliminating that. That's because ultimately everything is done on machine >> objects (bytes, words, dwords, etc.) and you always need a loop if you >> are >> going to operate on more than one. > > I still don't understand why is it relevant. Ada already has "loops" you > are talking about for String and Wide_String. Why cannot you use them for > their representations after selecting through dispatch? You can - but there is no benefit to doing so, so why bother? >> Because of that, there is almost no value to slicing operations unless >> you >> know the representation and can use block move instructions. > > I want to be able to pass a slice to Put_Line without copying. I want to win the Powerball so I can use the money to advance Ada and programming. Doesn't mean that it's practical or possible. >> There's nothing that you can do with a slice that you can't do with a >> loop, >> and usually the loop is easier to write and understand. > > Are you suggesting to call Put from a loop instead of Put_Line? I Don't > want the language forcing me doing that. You need a loop somewhere (or a complex abstraction); I suggest it be done at the call-site because there is insufficient value to doing it elsewhere. In your particular example, that means that the slice needs to be a new object. That doesn't necessarily mean copying of the data. If the designer of the abstraction, have put in enough smarts to share representations -- after all, if Unbounded_String can do it, so can Unbounded_UTF8_String. But as with Unbounded_String, I don't think the language should get involved in this. A compiler can copy a slice of an String any time it wants in Ada today -- I see no reason to change that. (And Janus/Ada uses that to support generic sharing in some instances.) ... >> Slicing is already impossible for the case that we're talking about, > > ? > > Normal strings have slices and should continue to have them. Sure, but Root_String'Class is a separate type hierarchy. I don't think there can be any sharing between them other than through a set of defined conversions. If we go this way, new programs should avoid String and Wide_String altogether (there would be a new type rooted at Root_String that provided those representations). >> and >> interface to foreign language already has to be done through special >> types. > > Which should certainly be in the same class! There is no semantic reason > why char_array should not be considered string. It won't work, semantically or implementation-wise. This is a total restart of String semantics, and the old semantics will still exist (probably in Annex J). There is no way to make the existing array semantics work like a tagged type, and that is absolutely necessary for dispatching to work (even if it isn't a "tagged type" in Ada terms). ... >> No I mean all objects. It should be none of your business how the >> compiler >> implements objects > > On the contrary, the compiler is free to choose a representation under the > constraints specified by the programmer. I don't want Ada to become C#. That's the same thing I said, so I don't know why you are claiming that this is different. The compiler always has the power to reject things the programmer specifies if it can't implement them. (The "Recommended Level of Support" puts some minimum requires on what ought to be supported.) ... >> None of the above makes any sense whatsoever. We need all of those things >> in >> the object in order to generate code. > > So, you want to describe all possible problem domains in the RM? The RM > should know that a matrix of 2 rows and 5 columns can be multiplied to a > 5x8 matrix, but not to a 8x8 matrix? Good luck with that! No, but we need the building blocks so that one can specify such things as part of the language. >> I suspect that if your model became the law of the land, compilers would >> generate very bad code for any cases like the ones you want, and you >> wouldn't be able to use the result anyway. > > Nobody tried. But I doubt it. My proposals have a goal to significantly > simplify the language. Ada 2005 and 2012 added a huge number of special > cases requiring special treatment. That surely complicates optimization of > Ada programs which is already not great. Smaller and more regular language > would be easier to optimize. The definition of the language doesn't have much effect on the ability to optimize (almost everything that does is in the infamous 11.6). Optimization is almost completely done on language-independent intermediate codes, so the language definition only comes into play if some normal optimization has to be blocked (there are a few cases of this in Ada). A simpler definition *might* be easier to interpret and convert to that intermediate code, but it is just as likely that it would have to be completely implemented by run-time structures (like type tags) that defy optimization. ... > This is a totally bogus argument. OO imposes no overhead on specific > types. That's kool-aid invented by the Ada 9x team. It's not remotely true, especially as all usable OOP types have to be controlled. ... > Nobody proposes to change tagged types. The idea is to add classes to > non-tagged types by adding tag to the class-wide object while keeping > specific objects as-is. But there is no point in doing so. Inheritance of operations of discrete types is a bad idea that Ada already has and is virtually useless. Why go further down a path to nowhere? ... >>> Container libraries need to be implemented as well. I don't want to >>> expose >>> access type, I want referential semantics. >> >> And that's the point of 4.1.5. The only thing you can't do is write "new" > > (what about 'Access? What about Unchecked_Deallocation?) Huh? Unchecked_Deallocation is a procedure, and you surely can write a procedure. Since you can't use new, there is no point in using the predefined unchecked_deallocation anyway (it only works on objects allocated by new). If you really need these things, use storage pools and don't even think about changing the access values. I don't see any way to use 'Access with a safe abstraction; it's always illegal so you have to use 'Unchecked_Access and create dangling pointers. >> that way, but calling a function to do that doesn't seem that bad. > > How do I put such a reference in an array, for example? 4.1.5 would be > extremely difficult to use for intended purpose. It's just a tagged object, do with it what you want. I don't see why you think there is a problem. ... >> Ahh, but that was a case where the "existing semantics" was good enough >> so >> we didn't create a new thing. This is a very special access type, one >> that >> almost never can be copied -- for practical purposes it can only be >> dereferenced. That's what we needed. Note that there is no intent that >> anyone ever create an object for this access type (and that is where all >> of >> the problems lie). It just has the syntax of an access type so we didn't >> have to invent a new thing to get dereferencing. > > You have a very specific use case in mind, namely containers. There is a > whole world outside that, for which what you said is untrue, e.g. for > smart > pointers. The thing not only exposes access, it also exposes the target > type. You have to expose the target type in order to have strong typing. How could you hide it and still make type checks? > For smart pointers and handles you might what to hide both. Consider > a handle to a file. You certainly don't want to make File_Descriptor it > points to, visible. You want the handle to implement file I/O interface > routed privately to the descriptor. You also want handles be copyiable and > comparable, but treated as references to some opaque limited object. I don't see the problem -- here the target type would be private (that Ada's for "opaque", of course). And in all honesty, if you want an opaque handle, I don't see any reason that you would want to do a visible dereference of it. The ONLY reason that we need 4.1.5 is so that we can assign directly into the target type. For all other purposes, accessor functions work just as well, so you would be better off using them in such cases. Needing to write into parts of objects accessed by handles is a container-like problem. In other cases, using regular Ada 95-style code works just fine (as we did in the Ada 2005 version of the containers library). ... >>> Even if it were compile-time it would require same representation for >>> all >>> involved objects. How would I do it for Unsigned_1 and String? >> >> I don't see this necessarily. You certainly can use dispatching to >> support >> different representations. > > No way. Consider operation Send: > > procedure Send (To : in out Register; Value : Unsigned_1); > > procedure Send (To : in out Register; Value : String); > > It cannot dispatch! Firstly, Unsigned_1 and String are not in the same > class. Secondly, even if they were, it would be MD! So, you need MI and MD > to make it happen. Without them, poor man's solution is messing with > generics. If you really wanted to go this way, you'd put all of those types in the same class. (Having every possible advantage without any disadvantages is impossible.) You are right about multiple dispatch in some cases, although it's usually possible to layer those: procedure Send (To : in out Register; Value : Data'Class); which is legal Ada. You then have to dispatch to somehow marshall the values (streams would work in this case, although you'd probably want to have a private version for your own use). I admit I don't see any point to a tagged Register type, but I take your word for it that there is some value to that. ... >> I think >> these need a balance, especially as modern static analyzers can remove >> the >> vast majority of them (or warn that they might fail, which is a cause for >> concern). > > It is not about removing checks, though performance is a concern too. The > major problem is that failed checks must be flagged as errors. You are a > compiler writer, I am designing automation systems. To me run-time check > is > much too late. A fault can break real things, apart from maintenance. > Imagine Claw running on an oil platform. Do you own a helicopter? That's my point about static analysis. Such a tool should be able to prove that the majority of run-time checks can't happen, and give you a list of those remaining. (That's assuming appropriate declarations and assertions, of course). The only ones that you have to worry about are those that can't be proved. Of course, that depends on the underlying platform. If Claw is running on an oil platform, you've got problems because that's running on top of Windows. And we can't guess why or when Windows will fail something. So pretty much everything comes down to run-time checks. You can mitigate problems with run-time checks with last-chance error handlers and the like. But I'd prefer to prove they don't happen -- without constraining the language and programs to the point where you can't write anything realistic (the SPARK problem). That appears like more run-time checks (in terms of how you write the code), but the ultimate result is just as safe (and much less complicated, so it's a lot more likely to be right -- I'd never trust any program with more than a handful of generics, it's just too hard to get the compilers to handle those right). Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-23 2:33 ` Randy Brukardt @ 2013-03-23 4:44 ` Shark8 2013-03-25 22:24 ` Randy Brukardt 2013-03-23 9:53 ` Dmitry A. Kazakov 1 sibling, 1 reply; 242+ messages in thread From: Shark8 @ 2013-03-23 4:44 UTC (permalink / raw) On Friday, March 22, 2013 8:33:02 PM UTC-6, Randy Brukardt wrote: > > I'd never trust any program with more than a handful of generics, it's just > too hard to get the compilers to handle those right). That seems a bit odd... I would think that once you had a generic* method for handling overloading you could apply that to generics as well. [* Pun intended.] ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-23 4:44 ` Shark8 @ 2013-03-25 22:24 ` Randy Brukardt 2013-03-26 1:15 ` Shark8 0 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-03-25 22:24 UTC (permalink / raw) "Shark8" <onewingedshark@gmail.com> wrote in message news:c231e327-0859-4430-adfc-ed4de4de2208@googlegroups.com... > On Friday, March 22, 2013 8:33:02 PM UTC-6, Randy Brukardt wrote: >> >> I'd never trust any program with more than a handful of generics, it's >> just >> too hard to get the compilers to handle those right). > > That seems a bit odd... I would think that once you had a generic* method > for handling overloading you could apply that to generics as well. > > [* Pun intended.] It's the combination of a wealth of things, overloading is the easy one. Certainly a shared implementation (like the one in Janus/Ada) makes everything harder, but there are enough oddities in the handling of formals that it won't ever be easy. It's really the result of having a strong contract model for generics; that prevents using simple textual substitution for thing. Of course, you need a strong contract model if you want the generic to be correct without knowing anything about the instantiations. (Same as you do for subprograms.) Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-25 22:24 ` Randy Brukardt @ 2013-03-26 1:15 ` Shark8 0 siblings, 0 replies; 242+ messages in thread From: Shark8 @ 2013-03-26 1:15 UTC (permalink / raw) On Monday, March 25, 2013 4:24:10 PM UTC-6, Randy Brukardt wrote: > "Shark8" <onewingedshark@gmail.com> wrote in message > > news:c231e327-0859-4430-adfc-ed4de4de2208@googlegroups.com... > > > On Friday, March 22, 2013 8:33:02 PM UTC-6, Randy Brukardt wrote: > >> > >> I'd never trust any program with more than a handful of generics, it's > >> just > >> too hard to get the compilers to handle those right). > > > > That seems a bit odd... I would think that once you had a generic* method > > for handling overloading you could apply that to generics as well. > > > > [* Pun intended.] > > It's the combination of a wealth of things, overloading is the easy one. After posting -- and thinking about it a little more -- I did suspect that would be the case. {Though I would certainly love to hear the "whyfor" it's harder than overloading.} > Certainly a shared implementation (like the one in Janus/Ada) makes > everything harder, That reminds me: I need to consider getting a copy of Janus/Ada when/if I ever restart my OS-project idea. -- I do think an OS based entirely in Ada {except, *maybe*, the boot-loader} could be a much better foundation than the [general purpose] OSes we currently have. > but there are enough oddities in the handling of formals > that it won't ever be easy. Well, that's understandable given that generic [packages] have a lot more leeway in their 'discriminants' than discriminated-records. {According to http://www.cs.dartmouth.edu/reports/TR86-104.pdf records and generic-packages have a lot of overlap such that they are virtually entirely interchangeable... though this does raise the interesting possibility of unifying, on "the underside" of a compiler, a common format to handle both.} But speaking of unifying things, would it make things easier to have Float and Fixed unified w/ a common base? {So that, say, one could have an algorithm parametrized w/ one or the other and still work -- that could be useful for DSP and other embedded systems.} Perhaps a Universal_Radix could be imagined as the 'Base of Universal_Fixed and Universal_Float, having all the asthmatic-functions [and aspects and attributes] common to both. > It's really the result of having a strong > contract model for generics; that prevents using simple textual substitution > for thing. > I'm pretty sure textual substitution is almost always the wrong answer. When I was working on a web-based program (handling medical records[!]) one of the modules included text-based merge-fields using textual substitution... it was horribly, horribly fragile. > Of course, you need a strong contract model if you want the > generic to be correct without knowing anything about the instantiations. > (Same as you do for subprograms.) True -- though if Ada does get a bit more attention/popularity there's likely going to be a push for the ARG to reduce contracts's strength. I think a lot of some [new to Ada] people's difficulties could be alleviated somewhat by subverting their wish to subvert the type-system with, perhaps, a user-defined attribute "To_Type'Convert( From_Type_Var )" used in much the same manner we handle stream-attributes... though it would have to support overloading (and I'm not sure that is such a good idea in an attribute). ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-23 2:33 ` Randy Brukardt 2013-03-23 4:44 ` Shark8 @ 2013-03-23 9:53 ` Dmitry A. Kazakov 2013-03-25 22:58 ` Randy Brukardt 1 sibling, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-23 9:53 UTC (permalink / raw) On Fri, 22 Mar 2013 21:33:02 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:2qwq2cdeuvhu$.qtnb8zyhuob9$.dlg@40tude.net... >> I still don't understand why is it relevant. Ada already has "loops" you >> are talking about for String and Wide_String. Why cannot you use them for >> their representations after selecting through dispatch? > > You can - but there is no benefit to doing so, so why bother? Egh, we wanted a class of strings, didn't we? >>> There's nothing that you can do with a slice that you can't do with a >>> loop, and usually the loop is easier to write and understand. >> >> Are you suggesting to call Put from a loop instead of Put_Line? I Don't >> want the language forcing me doing that. > > You need a loop somewhere (or a complex abstraction); Yes, the loop shall be within Put_Line. > In your particular example, that means that the slice needs to be a new > object. It certainly is, already. > That doesn't necessarily mean copying of the data. If the designer > of the abstraction, have put in enough smarts to share representations -- > after all, You should break your mental block. No shared representation, I want different representations for different string types. >>> Slicing is already impossible for the case that we're talking about, >> >> ? >> >> Normal strings have slices and should continue to have them. > > Sure, but Root_String'Class is a separate type hierarchy. I see, yet another outhouse, also. Ada quickly becomes a shantytown... >>> and >>> interface to foreign language already has to be done through special >>> types. >> >> Which should certainly be in the same class! There is no semantic reason >> why char_array should not be considered string. > > It won't work, semantically or implementation-wise. This is a total restart > of String semantics, and the old semantics will still exist (probably in > Annex J). There is no way to make the existing array semantics work like a > tagged type, and that is absolutely necessary for dispatching to work (even > if it isn't a "tagged type" in Ada terms). The way is to allow untagged T to have T'Class. This will preserve all semantics and all existing representations. Not even an explicit root type is needed, e.g. for char_array. The technique makes it possible to have ad-hoc supertypes, which would serve the purpose, e.g. you would define Put_Line on such a supertype and it will work for both String and char_array. Not a line changed in Standard or Interfaces.C. >>> No I mean all objects. It should be none of your business how the >>> compiler implements objects >> >> On the contrary, the compiler is free to choose a representation under the >> constraints specified by the programmer. I don't want Ada to become C#. > > That's the same thing I said, so I don't know why you are claiming that this > is different. It is different becauseto me it should be up to the programmer to set these constraints. The constraint is that char_array is a sequence of aliased char without gaps. If the compiler does not know how to implement a particular string operation on char_array, it should ask me. >>> None of the above makes any sense whatsoever. We need all of those things >>> in the object in order to generate code. >> >> So, you want to describe all possible problem domains in the RM? The RM >> should know that a matrix of 2 rows and 5 columns can be multiplied to a >> 5x8 matrix, but not to a 8x8 matrix? Good luck with that! > > No, but we need the building blocks so that one can specify such things as > part of the language. And the building block necessary is a statically checked constraint. The check shall be user-defined. The constraint shall be not present in constrained objects. This building block would give everything needed to have string class as well. >> This is a totally bogus argument. OO imposes no overhead on specific >> types. > > That's kool-aid invented by the Ada 9x team. It's not remotely true, > especially as all usable OOP types have to be controlled. See above. T'Class for all types! >> Nobody proposes to change tagged types. The idea is to add classes to >> non-tagged types by adding tag to the class-wide object while keeping >> specific objects as-is. > > But there is no point in doing so. Inheritance of operations of discrete > types is a bad idea that Ada already has and is virtually useless. ? > Why go further down a path to nowhere? Not even single step made so far. I see a lot of ad-hocks added recently which directly influence discrete types. All these aspects, attributes ('Read) are defined on discrete types as well. You are dragged down the path, looking backwards... >> How do I put such a reference in an array, for example? 4.1.5 would be >> extremely difficult to use for intended purpose. > > It's just a tagged object, do with it what you want. I don't see why you > think there is a problem. We will see. My prediction is that 4.1.5 will be very rarely used. Those who will try it, will have to fight with language limitations imposed by the design and then will drop it. Libraries based on it, will in turn become difficult to use for average programmers. Too much mental overhead, too many helper types (a bad OO-fest), too much time to find the package where the mess resides, too much efforts to understand why the compiler rejected obvious code... >>> Ahh, but that was a case where the "existing semantics" was good enough >>> so we didn't create a new thing. This is a very special access type, one >>> that almost never can be copied -- for practical purposes it can only be >>> dereferenced. That's what we needed. Note that there is no intent that >>> anyone ever create an object for this access type (and that is where all >>> of the problems lie). It just has the syntax of an access type so we didn't >>> have to invent a new thing to get dereferencing. >> >> You have a very specific use case in mind, namely containers. There is a >> whole world outside that, for which what you said is untrue, e.g. for >> smart pointers. The thing not only exposes access, it also exposes the target >> type. > > You have to expose the target type in order to have strong typing. How could > you hide it and still make type checks? Why should target type be public? > The ONLY reason that we need 4.1.5 is so that we can assign directly > into the target type. Yes, it is a hack designed for single use case. >>>> Even if it were compile-time it would require same representation for all >>>> involved objects. How would I do it for Unsigned_1 and String? >>> >>> I don't see this necessarily. You certainly can use dispatching to >>> support different representations. >> >> No way. Consider operation Send: >> >> procedure Send (To : in out Register; Value : Unsigned_1); >> >> procedure Send (To : in out Register; Value : String); >> >> It cannot dispatch! Firstly, Unsigned_1 and String are not in the same >> class. Secondly, even if they were, it would be MD! So, you need MI and MD >> to make it happen. Without them, poor man's solution is messing with >> generics. > > If you really wanted to go this way, you'd put all of those types in the > same class. (Having every possible advantage without any disadvantages is > impossible.) You are right about multiple dispatch in some cases, although > it's usually possible to layer those: > > procedure Send (To : in out Register; Value : Data'Class); > > which is legal Ada. Sure, this is exactly how I do it. It bursts into dozens of generic packages and hundreds of their instances. Unless you propose to code all hundreds of combinations manually... How should I test THIS? > I admit I don't see any point to a tagged Register type, but I take your > word for it that there is some value to that. Register must be tagged because Send is an operation on the register [and ultimately on the device the register refers to] >>> I think >>> these need a balance, especially as modern static analyzers can remove >>> the >>> vast majority of them (or warn that they might fail, which is a cause for >>> concern). >> >> It is not about removing checks, though performance is a concern too. The >> major problem is that failed checks must be flagged as errors. You are a >> compiler writer, I am designing automation systems. To me run-time check >> is much too late. A fault can break real things, apart from maintenance. >> Imagine Claw running on an oil platform. Do you own a helicopter? > > That's my point about static analysis. Such a tool should be able to prove > that the majority of run-time checks can't happen, and give you a list of > those remaining. I don't need any list. Should I send it to my customers? I need the program fail to compile when writing analogue input. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-23 9:53 ` Dmitry A. Kazakov @ 2013-03-25 22:58 ` Randy Brukardt 2013-03-26 10:52 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-03-25 22:58 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:a96esjwiniqy$.op3wh7x9wrsl.dlg@40tude.net... > On Fri, 22 Mar 2013 21:33:02 -0500, Randy Brukardt wrote: ... >> That doesn't necessarily mean copying of the data. If the designer >> of the abstraction, have put in enough smarts to share representations -- >> after all, > > You should break your mental block. No shared representation, I want > different representations for different string types. I was talking about sharing representations of *different* objects of the same string type (for instance, a string variable and a slice of that variable - that case, sharing the data might be preferred to copying it). Not talking about different types here; of course, the whole point of changing anything here is to allow different representations of the data. >>>> Slicing is already impossible for the case that we're talking about, >>> >>> ? >>> >>> Normal strings have slices and should continue to have them. >> >> Sure, but Root_String'Class is a separate type hierarchy. > > I see, yet another outhouse, also. Ada quickly becomes a shantytown... Unifying old junk it's possible without serious breakage of existing code, which is intolerable. It's better to start over and obsolete the old stuff. >>>> and >>>> interface to foreign language already has to be done through special >>>> types. >>> >>> Which should certainly be in the same class! There is no semantic reason >>> why char_array should not be considered string. >> >> It won't work, semantically or implementation-wise. This is a total >> restart >> of String semantics, and the old semantics will still exist (probably in >> Annex J). There is no way to make the existing array semantics work like >> a >> tagged type, and that is absolutely necessary for dispatching to work >> (even >> if it isn't a "tagged type" in Ada terms). > > The way is to allow untagged T to have T'Class. This will preserve all > semantics and all existing representations. Not even an explicit root type > is needed, e.g. for char_array. The technique makes it possible to have > ad-hoc supertypes, which would serve the purpose, e.g. you would define > Put_Line on such a supertype and it will work for both String and > char_array. Not a line changed in Standard or Interfaces.C. Sounds great, but it won't work in practice. You'd introduce a lot of ambiguities and break existing code that way. (That's why Ada.Strings.Unbounded_String doesn't have string literals; we couldn't find any way to add them without making most existing code using the package ambiguous.) Secondly, the inheritance and overriding of untagged types is much looser than the that of tagged types; you don't even have to use the same parameter modes. That's not going to be compatible with dispatching, so you would have to make quite a bit of existing types illegal if you want to truly support Untagged'Class. (We had to introduce such an incompatibility when we "fixed" equality for untagged record types, and it was very controversal. I doubt that we would risk going further.) I'm also dubious that good code can be generated for such a model, but that's a secondary concern vs. the incompatibility. ... ... >>> This is a totally bogus argument. OO imposes no overhead on specific >>> types. >> >> That's kool-aid invented by the Ada 9x team. It's not remotely true, >> especially as all usable OOP types have to be controlled. > > See above. T'Class for all types! See above -- this model is likely impossible for Ada. (It might work fine in a new language, but that's irrelevant here.) ... >> Why go further down a path to nowhere? > > Not even single step made so far. I see a lot of ad-hocks added recently > which directly influence discrete types. All these aspects, attributes > ('Read) are defined on discrete types as well. You are dragged down the > path, looking backwards... No choice. We can *add* new stuff, but changes to old stuff isn't possible. And dispatching is incompatible with untagged types, simply because Ada 83 got inheritance horribly wrong, and we're stuck with that. >>> How do I put such a reference in an array, for example? 4.1.5 would be >>> extremely difficult to use for intended purpose. >> >> It's just a tagged object, do with it what you want. I don't see why you >> think there is a problem. > > We will see. My prediction is that 4.1.5 will be very rarely used. Those > who will try it, will have to fight with language limitations imposed by > the design and then will drop it. Libraries based on it, will in turn > become difficult to use for average programmers. Too much mental overhead, > too many helper types (a bad OO-fest), too much time to find the package > where the mess resides, too much efforts to understand why the compiler > rejected obvious code... Like generics, the expectation is that hardly anyone will need to understand how it works. Just use it and get the expected semantics. And the compiler shouldn't be rejecting any obvious code unless the definition is screwed up. (That's the fault of the guru who set it up, not the user.) There are large parts of Ada that aren't really expected to be used by "mere mortals". Generics, storage pools, generalized references and indexes, iterators, etc. In all of these cases, they really exist to make library packages easier to use; most users will use these things without worrying too much about how they're implemented. I originally had a different model for 4.1.5 (most custom rules), but we determined that most of rules we needed already existed in the language. So it ended up a bit more complex (using a discriminant) in order to have far fewer new rules. That's usually a preferred trade-off. ... >>> You have a very specific use case in mind, namely containers. There is a >>> whole world outside that, for which what you said is untrue, e.g. for >>> smart pointers. The thing not only exposes access, it also exposes the >>> target >>> type. >> >> You have to expose the target type in order to have strong typing. How >> could >> you hide it and still make type checks? > > Why should target type be public? How do you enforce strong typing without that being the case? If you don't know what the target is, how do you determine how the resulting object can be used? (The type being public doesn't mean that the *contents* of the type are public -- of course the target could be an Ada private type.) The whole point of this construct is to *dereference* a referential access (no special feature is needed to define a handle, after all, we've been doing that since the beginning of Ada time). >> The ONLY reason that we need 4.1.5 is so that we can assign directly >> into the target type. > > Yes, it is a hack designed for single use case. There is no other need, everything else can be done with functions and procedures. Even this assignment can be done with a procedure, but such a procedure cannot compose or support extensions. ... .... >> If you really wanted to go this way, you'd put all of those types in the >> same class. (Having every possible advantage without any disadvantages is >> impossible.) You are right about multiple dispatch in some cases, >> although >> it's usually possible to layer those: >> >> procedure Send (To : in out Register; Value : Data'Class); >> >> which is legal Ada. > > Sure, this is exactly how I do it. It bursts into dozens of generic > packages and hundreds of their instances. Unless you propose to code all > hundreds of combinations manually... How should I test THIS? Testing is close to worthless. Ensure that the code is right in the first place (admittedly hard), and use a bit of testing for acceptance. Testing never proves any sort of correctness; all of the many thousands of hours of testing on our compiler never did anything to make it more reliable -- that all happened by better design. At best, the testing just prevented reintroduction of old bugs. ... >> That's my point about static analysis. Such a tool should be able to >> prove >> that the majority of run-time checks can't happen, and give you a list of >> those remaining. > > I don't need any list. Should I send it to my customers? I need the > program > fail to compile when writing analogue input. Treat the list as failures if you must, and insist that it be empty before shipping. That's a reasonable approach in some environments. But I think you'll find it's too hard to accomplish, just like it's too hard to do complete code coverage (hard to test error handlers) and it's too hard to make everything generic. I'd rather prioritize such issues, and only worry about the ones in mainline code. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-25 22:58 ` Randy Brukardt @ 2013-03-26 10:52 ` Dmitry A. Kazakov 2013-03-26 21:31 ` Randy Brukardt 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-26 10:52 UTC (permalink / raw) On Mon, 25 Mar 2013 17:58:26 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:a96esjwiniqy$.op3wh7x9wrsl.dlg@40tude.net... >> On Fri, 22 Mar 2013 21:33:02 -0500, Randy Brukardt wrote: > ... >>> That doesn't necessarily mean copying of the data. If the designer >>> of the abstraction, have put in enough smarts to share representations -- >>> after all, >> >> You should break your mental block. No shared representation, I want >> different representations for different string types. > > I was talking about sharing representations of *different* objects of the > same string type (for instance, a string variable and a slice of that > variable - that case, sharing the data might be preferred to copying it). OK, the representation would be for type-specific string objects: bounds + pointer and for class-wide string objects: tag + bounds + pointer >>>>> Slicing is already impossible for the case that we're talking about, >>>> >>>> ? >>>> >>>> Normal strings have slices and should continue to have them. >>> >>> Sure, but Root_String'Class is a separate type hierarchy. >> >> I see, yet another outhouse, also. Ada quickly becomes a shantytown... > > Unifying old junk it's possible without serious breakage of existing code, > which is intolerable. Why is it junk? There is nothing wrong with String, Wide_String, Wide_Wide_String. They should stay. Unbounded_String is indeed junk, but after adding an array interface to it = putting it into the same hierarchy it would perfectly serve the purpose. >> The way is to allow untagged T to have T'Class. This will preserve all >> semantics and all existing representations. Not even an explicit root type >> is needed, e.g. for char_array. The technique makes it possible to have >> ad-hoc supertypes, which would serve the purpose, e.g. you would define >> Put_Line on such a supertype and it will work for both String and >> char_array. Not a line changed in Standard or Interfaces.C. > > Sounds great, but it won't work in practice. You'd introduce a lot of > ambiguities and break existing code that way. Why? The effect is limited strictly to T'Class objects, which presently do not exist. > (That's why > Ada.Strings.Unbounded_String doesn't have string literals; we couldn't find > any way to add them without making most existing code using the package > ambiguous.) This is a different problem. I think the model is that string and other literals would become primitive operations. Upon inheritance in the class sense, they should be overridden or else dropped. There should be some syntax invented for handling literals, e.g, some factory operation etc. An alternative is having literals class-wide, which roughly corresponds to existing Universal_String approach. In both cases you might wish to add some preference rules [we already have some] to keep it compatible and slash ambiguities. It would be worth to consider a possibility for the user to control such preference rules and to have user-defined literals in general. > Secondly, the inheritance and overriding of untagged types is much looser > than the that of tagged types; you don't even have to use the same parameter > modes. Yes, but untagged types in the model I have in mind will remain independent types, they would not suddenly become Ada-subtypes, if you mean that. So subtype S is String ...; type Q is new String ...; would have different semantics, just like they do for tagged types already. > And dispatching is incompatible with untagged types, simply because Ada 83 > got inheritance horribly wrong, and we're stuck with that. I disagree. It seems fully compatible with Ada 83 because T'Class would be a distinct type with objects of that type. It is orthogonal to Ada-subtypes. You will not dispatch on Positive vs. Integer, these will reman specific [sub]types. In order to dispatch you will need a class-wide object of the type Integer'Class (which will be strictly same as Positive'Class, except, possibly, the constraint). That object will have the representation tag + value. For Integer and Positive objects nothing changes. We might consider redefining some existing operations to become class-wide in some arguments, but that is another story. >>>> You have a very specific use case in mind, namely containers. There is a >>>> whole world outside that, for which what you said is untrue, e.g. for >>>> smart pointers. The thing not only exposes access, it also exposes the >>>> target type. >>> >>> You have to expose the target type in order to have strong typing. How >>> could you hide it and still make type checks? >> >> Why should target type be public? > > How do you enforce strong typing without that being the case? If you don't > know what the target is, how do you determine how the resulting object can > be used? Target and handle types usually implement some public interface. E.g. type File_Access is limited interface; procedure Write (File : in out File_Access; Data : ...) is abstract; ... Somewhere else type File_Descriptor is ... limited ... and File_Access ...; Somewhere else type File_Handle is ... and File_Access ...; >>> If you really wanted to go this way, you'd put all of those types in the >>> same class. (Having every possible advantage without any disadvantages is >>> impossible.) You are right about multiple dispatch in some cases, >>> although it's usually possible to layer those: >>> >>> procedure Send (To : in out Register; Value : Data'Class); >>> >>> which is legal Ada. >> >> Sure, this is exactly how I do it. It bursts into dozens of generic >> packages and hundreds of their instances. Unless you propose to code all >> hundreds of combinations manually... How should I test THIS? > > Testing is close to worthless. But this is the only choice if your checks are dynamic. If you don't like testing then you should understand why I don't buy dynamic checks [mis]used to detect bugs. >>> That's my point about static analysis. Such a tool should be able to prove >>> that the majority of run-time checks can't happen, and give you a list of >>> those remaining. >> >> I don't need any list. Should I send it to my customers? I need the >> program fail to compile when writing analogue input. > > Treat the list as failures if you must, and insist that it be empty before > shipping. So, I need an AI system to parse compiler messages (of various vendors) on top? -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-26 10:52 ` Dmitry A. Kazakov @ 2013-03-26 21:31 ` Randy Brukardt 2013-03-27 9:37 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-03-26 21:31 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:1u72u7h5j4jg3$.wlxmaltyzqik.dlg@40tude.net... > On Mon, 25 Mar 2013 17:58:26 -0500, Randy Brukardt wrote: > >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >> news:a96esjwiniqy$.op3wh7x9wrsl.dlg@40tude.net... >>> On Fri, 22 Mar 2013 21:33:02 -0500, Randy Brukardt wrote: >> ... >>>> That doesn't necessarily mean copying of the data. If the designer >>>> of the abstraction, have put in enough smarts to share >>>> representations -- >>>> after all, >>> >>> You should break your mental block. No shared representation, I want >>> different representations for different string types. >> >> I was talking about sharing representations of *different* objects of the >> same string type (for instance, a string variable and a slice of that >> variable - that case, sharing the data might be preferred to copying it). > > OK, the representation would be for type-specific string objects: > > bounds + pointer > > and for class-wide string objects: > > tag + bounds + pointer Sure, but irrelevant. The question is whether slicing copies the data or not. If it is a new object, the data must be copied logically, but my point was that it would be possible for an abstraction to defer actually making a copy until an assignment is actually done. It's still a copy. ... >> Unifying old junk it's possible without serious breakage of existing >> code, >> which is intolerable. > > Why is it junk? There is nothing wrong with String, Wide_String, > Wide_Wide_String. They should stay. They're junk because they can't be unified without serious breakage of existing code. Since we're not willing to break those eggs, we have to start over. > Unbounded_String is indeed junk, but after adding an array interface to it > = putting it into the same hierarchy it would perfectly serve the purpose. That's the idea, but of course that requires starting over with it. >>> The way is to allow untagged T to have T'Class. This will preserve all >>> semantics and all existing representations. Not even an explicit root >>> type >>> is needed, e.g. for char_array. The technique makes it possible to have >>> ad-hoc supertypes, which would serve the purpose, e.g. you would define >>> Put_Line on such a supertype and it will work for both String and >>> char_array. Not a line changed in Standard or Interfaces.C. >> >> Sounds great, but it won't work in practice. You'd introduce a lot of >> ambiguities and break existing code that way. > > Why? The effect is limited strictly to T'Class objects, which presently do > not exist. Not true, as I explained later in my note. The possibility of dispatching changes a lot of rules about inheritance and assignment. >> (That's why >> Ada.Strings.Unbounded_String doesn't have string literals; we couldn't >> find >> any way to add them without making most existing code using the package >> ambiguous.) > > This is a different problem. I think the model is that string and other > literals would become primitive operations. Upon inheritance in the class > sense, they should be overridden or else dropped. There should be some > syntax invented for handling literals, e.g, some factory operation etc. An > alternative is having literals class-wide, which roughly corresponds to > existing Universal_String approach. In both cases you might wish to add > some preference rules [we already have some] to keep it compatible and > slash ambiguities. It would be worth to consider a possibility for the > user > to control such preference rules and to have user-defined literals in > general. But that's not the problem; that was what we wanted to do. The problem is that Unbounded string has two versions of most operations, one that takes String and one that takes Unbounded_String. If you gave literals to Unbounded_String, all of the operations which took both would be ambiguous for literals unless you qualified them. Which defeats the purpose. We could solve the problem by getting rid of all of the routines that take String parameters, but that of course woulc break any code that passed slices or objects of type String. So the only fix here is to start over with a new package, keeping the old one around for existing code. >> Secondly, the inheritance and overriding of untagged types is much looser >> than the that of tagged types; you don't even have to use the same >> parameter >> modes. > > Yes, but untagged types in the model I have in mind will remain > independent > types, they would not suddenly become Ada-subtypes, if you mean that. So > > subtype S is String ...; > type Q is new String ...; > > would have different semantics, just like they do for tagged types > already. > >> And dispatching is incompatible with untagged types, simply because Ada >> 83 >> got inheritance horribly wrong, and we're stuck with that. > > I disagree. It seems fully compatible with Ada 83 because T'Class would be > a distinct type with objects of that type. It is orthogonal to > Ada-subtypes. You will not dispatch on Positive vs. Integer, these will > reman specific [sub]types. In order to dispatch you will need a class-wide > object of the type Integer'Class (which will be strictly same as > Positive'Class, except, possibly, the constraint). That object will have > the representation tag + value. For Integer and Positive objects nothing > changes. We might consider redefining some existing operations to become > class-wide in some arguments, but that is another story. You missed the point altogether. You can't dispatch in general on untagged types because overriding operations may have different modes and subtypes for the parameters. So what *is* the profile of the operation for T'Class, and how can it work? Consider: Type Int is range 1 .. 10; procedure Op (A, B : in Int); Type Der is new Int; overriding procedure Op (A : in out Der; B : in Der); Obj : Int'Class := Der'(1); Op (A => 1, B => Obj); -- Legal?? Here, we're dispatching to a routine with an "in out" parameter, passing a literal (because the profile of Op for Int'Class has an "in" parameter). Is this legal? If so, what does it mean? If not, how does that work if Der is added to the program later during maintenance. And if you say that Der cannot override Op this way, you're now incompatible with Ada 83- Ada 2012. >>>>> You have a very specific use case in mind, namely containers. There is >>>>> a >>>>> whole world outside that, for which what you said is untrue, e.g. for >>>>> smart pointers. The thing not only exposes access, it also exposes the >>>>> target type. >>>> >>>> You have to expose the target type in order to have strong typing. How >>>> could you hide it and still make type checks? >>> >>> Why should target type be public? >> >> How do you enforce strong typing without that being the case? If you >> don't >> know what the target is, how do you determine how the resulting object >> can >> be used? > > Target and handle types usually implement some public interface. E.g. > > type File_Access is limited interface; > procedure Write (File : in out File_Access; Data : ...) is abstract; > ... > > Somewhere else > > type File_Descriptor is ... limited ... and File_Access ...; > > Somewhere else > > type File_Handle is ... and File_Access ...; An interface can't have "..." as the parameter type for Write; there has to be something there. And that's the target type! Say again how it is that you are not exposing this type?? ... >>>> That's my point about static analysis. Such a tool should be able to >>>> prove >>>> that the majority of run-time checks can't happen, and give you a list >>>> of >>>> those remaining. >>> >>> I don't need any list. Should I send it to my customers? I need the >>> program fail to compile when writing analogue input. >> >> Treat the list as failures if you must, and insist that it be empty >> before >> shipping. > > So, I need an AI system to parse compiler messages (of various vendors) on > top? Huh? Why would you "parse" them? It's a binary choice (just as it is with ACATS testing): either require them to be removed or ignored. You only have to decide which classes of warnings you require to be removed from your code. For that, you have to understand your tools, sure, but if you don't understand your tools you are never going to get anywhere. A programming language definition is only a small part of getting programming right; it could never be more than 10% or so; the tools used provide another 20-30%. The rest is on the programmer's skills (to do good things like decrease coupling). Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-26 21:31 ` Randy Brukardt @ 2013-03-27 9:37 ` Dmitry A. Kazakov 2013-03-27 19:42 ` Randy Brukardt 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-27 9:37 UTC (permalink / raw) On Tue, 26 Mar 2013 16:31:35 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:1u72u7h5j4jg3$.wlxmaltyzqik.dlg@40tude.net... >> On Mon, 25 Mar 2013 17:58:26 -0500, Randy Brukardt wrote: >> >>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >>> news:a96esjwiniqy$.op3wh7x9wrsl.dlg@40tude.net... >>>> On Fri, 22 Mar 2013 21:33:02 -0500, Randy Brukardt wrote: >>> ... >>>>> That doesn't necessarily mean copying of the data. If the designer >>>>> of the abstraction, have put in enough smarts to share >>>>> representations -- >>>>> after all, >>>> >>>> You should break your mental block. No shared representation, I want >>>> different representations for different string types. >>> >>> I was talking about sharing representations of *different* objects of the >>> same string type (for instance, a string variable and a slice of that >>> variable - that case, sharing the data might be preferred to copying it). >> >> OK, the representation would be for type-specific string objects: >> >> bounds + pointer >> >> and for class-wide string objects: >> >> tag + bounds + pointer > > Sure, but irrelevant. The question is whether slicing copies the data or > not. If it is a new object, the data must be copied logically, No, logically it is a referential object. > but my point > was that it would be possible for an abstraction to defer actually making a > copy until an assignment is actually done. It's still a copy. Exactly the reverse, an implementation could be allowed to use a copy if that is consistent with the semantics of the slice being a reference. But regardless of the semantics, why this representation should not work? >>> Unifying old junk it's possible without serious breakage of existing >>> code, which is intolerable. >> >> Why is it junk? There is nothing wrong with String, Wide_String, >> Wide_Wide_String. They should stay. > > They're junk because they can't be unified without serious breakage of > existing code. A common ancestor would not break existing code. An ad-hoc ancestor could not do it even theoretically, because it is limited to the context where the ancestor is visible. >>> And dispatching is incompatible with untagged types, simply because Ada >>> 83 got inheritance horribly wrong, and we're stuck with that. >> >> I disagree. It seems fully compatible with Ada 83 because T'Class would be >> a distinct type with objects of that type. It is orthogonal to >> Ada-subtypes. You will not dispatch on Positive vs. Integer, these will >> reman specific [sub]types. In order to dispatch you will need a class-wide >> object of the type Integer'Class (which will be strictly same as >> Positive'Class, except, possibly, the constraint). That object will have >> the representation tag + value. For Integer and Positive objects nothing >> changes. We might consider redefining some existing operations to become >> class-wide in some arguments, but that is another story. > > You missed the point altogether. You can't dispatch in general on untagged > types because overriding operations may have different modes and subtypes > for the parameters. So what *is* the profile of the operation for T'Class, > and how can it work? > > Consider: > > Type Int is range 1 .. 10; > procedure Op (A, B : in Int); > > Type Der is new Int; This is not derivation within the class, it is a "type-cloning." Type cloning creates a new class and new a type (all types up the hierarchy). We need some syntax to indicate the difference. type Der is new Int <whatever>; It is unfortunate that tagged types reused "is new" for a purpose completely different from type cloning. Moreover, it is highly desired to that cloning were available for tagged types as well: package Original is new Ada.Containers.Vectors ...; type Clone is new Original.Vector; -- Cloning, not extending! Now, I have to hierarchies of Vector, not very useful in this particular case, because of missing helper types, but anyway. > overriding > procedure Op (A : in out Der; B : in Der); This is not an overriding since the mode is different. > Obj : Int'Class := Der'(1); > Op (A => 1, B => Obj); -- Legal?? MD is not fully implemented in Ada, but anyway, presuming that Op is a multi-method, that the mode is "in" and that 1 is Universal_Integer (is it?), the above is illegal because Op is not a method of Universal_Integer'Class. You would have to write it as: Op (A => Der'(1), B => Obj); -- Same tags Op (A => Int'(1), B => Obj); -- Different tags, Constraint_Error Multi-methods (a special case of MD) is another and long story. They should be properly supported in the end. > And if you say that Der cannot override Op this way, you're now incompatible > with Ada 83- Ada 2012. I want to preserve and extend type-cloning. >>>>>> You have a very specific use case in mind, namely containers. There is a >>>>>> whole world outside that, for which what you said is untrue, e.g. for >>>>>> smart pointers. The thing not only exposes access, it also exposes the >>>>>> target type. >>>>> >>>>> You have to expose the target type in order to have strong typing. How >>>>> could you hide it and still make type checks? >>>> >>>> Why should target type be public? >>> >>> How do you enforce strong typing without that being the case? If you don't >>> know what the target is, how do you determine how the resulting object can >>> be used? >> >> Target and handle types usually implement some public interface. E.g. >> >> type File_Access is limited interface; >> procedure Write (File : in out File_Access; Data : ...) is abstract; >> ... >> >> Somewhere else >> >> type File_Descriptor is ... limited ... and File_Access ...; >> >> Somewhere else >> >> type File_Handle is ... and File_Access ...; > > An interface can't have "..." as the parameter type for Write; there has to > be something there. procedure Write (File : in out File_Access; Data : Stream_Element_Array) is abstract; > And that's the target type! Say again how it is that you > are not exposing this type?? The target is File. I would gladly have MD and a hierarchy for the second parameter, but that is another story for now. >>>>> That's my point about static analysis. Such a tool should be able to prove >>>>> that the majority of run-time checks can't happen, and give you a list of >>>>> those remaining. >>>> >>>> I don't need any list. Should I send it to my customers? I need the >>>> program fail to compile when writing analogue input. >>> >>> Treat the list as failures if you must, and insist that it be empty >>> before shipping. >> >> So, I need an AI system to parse compiler messages (of various vendors) on >> top? > > Huh? Why would you "parse" them? Because whether a message is relevant to the choice if the program were OK to deploy depends now on the message content. The language does not help me anymore to indicate it as a bug. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-27 9:37 ` Dmitry A. Kazakov @ 2013-03-27 19:42 ` Randy Brukardt 2013-03-28 13:50 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-03-27 19:42 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:wdlyfbnwcnp7.10c9btwjmpm7j.dlg@40tude.net... > On Tue, 26 Mar 2013 16:31:35 -0500, Randy Brukardt wrote: > >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >> news:1u72u7h5j4jg3$.wlxmaltyzqik.dlg@40tude.net... >>> On Mon, 25 Mar 2013 17:58:26 -0500, Randy Brukardt wrote: >>> >>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >>>> news:a96esjwiniqy$.op3wh7x9wrsl.dlg@40tude.net... >>>>> On Fri, 22 Mar 2013 21:33:02 -0500, Randy Brukardt wrote: >>>> ... >>>>>> That doesn't necessarily mean copying of the data. If the designer >>>>>> of the abstraction, have put in enough smarts to share >>>>>> representations -- >>>>>> after all, >>>>> >>>>> You should break your mental block. No shared representation, I want >>>>> different representations for different string types. >>>> >>>> I was talking about sharing representations of *different* objects of >>>> the >>>> same string type (for instance, a string variable and a slice of that >>>> variable - that case, sharing the data might be preferred to copying >>>> it). >>> >>> OK, the representation would be for type-specific string objects: >>> >>> bounds + pointer >>> >>> and for class-wide string objects: >>> >>> tag + bounds + pointer >> >> Sure, but irrelevant. The question is whether slicing copies the data or >> not. If it is a new object, the data must be copied logically, > > No, logically it is a referential object. > >> but my point >> was that it would be possible for an abstraction to defer actually making >> a >> copy until an assignment is actually done. It's still a copy. > > Exactly the reverse, an implementation could be allowed to use a copy if > that is consistent with the semantics of the slice being a reference. > > But regardless of the semantics, why this representation should not work? The problem is that a slice ought to be a referential object as you put it, and a "regular" object is definitely *not* a referential object (a copy copies the data). I don't see any way for a single data type to have two different behaviors - as you've argued elsewhere, you can't have a single operation doing two different things. I suppose you could make a slice be a different type than a regular string object, but then you have problems with type matching (you want a slice to be compatible with the equivalent normal object). ... >>>> And dispatching is incompatible with untagged types, simply because Ada >>>> 83 got inheritance horribly wrong, and we're stuck with that. >>> >>> I disagree. It seems fully compatible with Ada 83 because T'Class would >>> be >>> a distinct type with objects of that type. It is orthogonal to >>> Ada-subtypes. You will not dispatch on Positive vs. Integer, these will >>> reman specific [sub]types. In order to dispatch you will need a >>> class-wide >>> object of the type Integer'Class (which will be strictly same as >>> Positive'Class, except, possibly, the constraint). That object will have >>> the representation tag + value. For Integer and Positive objects nothing >>> changes. We might consider redefining some existing operations to become >>> class-wide in some arguments, but that is another story. >> >> You missed the point altogether. You can't dispatch in general on >> untagged >> types because overriding operations may have different modes and subtypes >> for the parameters. So what *is* the profile of the operation for >> T'Class, >> and how can it work? >> >> Consider: >> >> Type Int is range 1 .. 10; >> procedure Op (A, B : in Int); >> >> Type Der is new Int; > > This is not derivation within the class, it is a "type-cloning." Type > cloning creates a new class and new a type (all types up the hierarchy). > We > need some syntax to indicate the difference. > > type Der is new Int <whatever>; > > It is unfortunate that tagged types reused "is new" for a purpose > completely different from type cloning. Nobody wants "type cloning". We waste a lot of mental energy getting rid of it in generics, for example. I have no idea why anyone that wants 'Class would want to avoid maximizing the interoperability of types. The original motivating example for Integer'Class was: Put (Obj : Integer'Class; Width : Count := 0); so that one didn't need to understand generic instantiations just to do simple I/O of strongly typed entities. I don't think a version of untagged'Class that did not work on existing derived types would fly. For no other reason than the fact that it would make tagged and untagged types more different, rather than less different. In any case, I didn't realize that you were making an entire new kind of type derivation - I wouldn't have guessed that someone that has been talking repeatedly about simplifying the language would add an entirely new kind of type to the language. > Moreover, it is highly desired to that cloning were available for tagged > types as well: > > package Original is new Ada.Containers.Vectors ...; > type Clone is new Original.Vector; -- Cloning, not extending! > > Now, I have to hierarchies of Vector, not very useful in this particular > case, because of missing helper types, but anyway. Pointless complication. I thought you were trying to simplify the language! >> overriding >> procedure Op (A : in out Der; B : in Der); > > This is not an overriding since the mode is different. It *is* an overriding in Ada 83, and it still is in Ada 2012. I agree that it should not have been, but that is irrelevant because we're stuck with it. >> Obj : Int'Class := Der'(1); >> Op (A => 1, B => Obj); -- Legal?? > > MD is not fully implemented in Ada, but anyway, presuming that Op is a > multi-method, that the mode is "in" and that 1 is Universal_Integer (is > it?), the above is illegal because Op is not a method of > Universal_Integer'Class. You would have to write it as: > > Op (A => Der'(1), B => Obj); -- Same tags > Op (A => Int'(1), B => Obj); -- Different tags, Constraint_Error This seems wrong; an integer literal usually gets its type from context. It's only a value of type Universal_Integer if there is no type given from context (as in a type conversion or number declaration). I was presuming that integer literals act as tag-indeterminate functions (the most sensible model; if you have constants for a tagged type you usually would model them as tag-indeterminate functions - for instance, the constants Zero and One in a universal arithmetic package), you don't need multiple dispatch: the Ada dispatching rules simply calls the correct version of the function for the tag of the object. And that's what we would want to happen for integer literals (that's the closest analogy to what happens for existing expressions). > Multi-methods (a special case of MD) is another and long story. They > should > be properly supported in the end. > >> And if you say that Der cannot override Op this way, you're now >> incompatible >> with Ada 83- Ada 2012. > > I want to preserve and extend type-cloning. And you claim that the ARG keeps building gazebos. You're building a lakeside floating pavillion. ;-) ... >> An interface can't have "..." as the parameter type for Write; there has >> to >> be something there. > > procedure Write (File : in out File_Access; Data : Stream_Element_Array) > is abstract; > >> And that's the target type! Say again how it is that you >> are not exposing this type?? > > The target is File. I would gladly have MD and a hierarchy for the second > parameter, but that is another story for now. OK, if the target is File, then you know that - that's public information. When you dereference a File_Handle, you get a File. You don't have to make the contents of File public, just it's name. So I still don't see why you think this is a problem. >>>>>> That's my point about static analysis. Such a tool should be able to >>>>>> prove >>>>>> that the majority of run-time checks can't happen, and give you a >>>>>> list of >>>>>> those remaining. >>>>> >>>>> I don't need any list. Should I send it to my customers? I need the >>>>> program fail to compile when writing analogue input. >>>> >>>> Treat the list as failures if you must, and insist that it be empty >>>> before shipping. >>> >>> So, I need an AI system to parse compiler messages (of various vendors) >>> on >>> top? >> >> Huh? Why would you "parse" them? > > Because whether a message is relevant to the choice if the program were OK > to deploy depends now on the message content. The language does not help > me > anymore to indicate it as a bug. But there is absolutely nothing new about this. GNAT has a variety of warnings (calling everything it displays a "warning" in order to avoid arguments about its particular classifications of message), but most people choose to treat some subset of them as errors that have to be removed before deployment. You would do that same; choose a *class* of warnings that have to be removed; there is no parsing of messages needed. If a warning in the prohibited class exists, the program is not ready for deployment. Yes, this means you need to develop a coding standard and a development standard to ensure that these these things are followed. But not having those in some form is just lousy programming management. And one thing we decided on the ARG long ago is that there is no way that a programming language can prevent lousy programming management -- any language can be misused without much effort. That cannot be prevented by a programming language; it's futile to try, and when you do try, you tend to make the language harder to use on real problems. So we assume competent management is used with Ada; we're not trying to make the language idiot-proof. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-27 19:42 ` Randy Brukardt @ 2013-03-28 13:50 ` Dmitry A. Kazakov 2013-03-28 21:55 ` Randy Brukardt 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-28 13:50 UTC (permalink / raw) On Wed, 27 Mar 2013 14:42:47 -0500, Randy Brukardt wrote: > The problem is that a slice ought to be a referential object as you put it, > and a "regular" object is definitely *not* a referential object (a copy > copies the data). What is "regular" object here? String? > I don't see any way for a single data type to have two > different behaviors These are two data types, string and slice. Are you treating slice as an Ada-subtype of string? I consider slice a member of same class as string, yet a distinct type (in Ada sense). This is like 4.1.5, but in the same type hierarchy. >>> You missed the point altogether. You can't dispatch in general on untagged >>> types because overriding operations may have different modes and subtypes >>> for the parameters. So what *is* the profile of the operation for T'Class, >>> and how can it work? >>> >>> Consider: >>> >>> Type Int is range 1 .. 10; >>> procedure Op (A, B : in Int); >>> >>> Type Der is new Int; >> >> This is not derivation within the class, it is a "type-cloning." Type >> cloning creates a new class and new a type (all types up the hierarchy). >> We need some syntax to indicate the difference. >> >> type Der is new Int <whatever>; >> >> It is unfortunate that tagged types reused "is new" for a purpose >> completely different from type cloning. > > Nobody wants "type cloning". It is a very useful building block to me. Anyway it is Ada 83 legacy. > I have no idea why anyone that wants 'Class > would want to avoid maximizing the interoperability of types. Sometimes we want types related, sometimes we don't, while reusing existing implementations. The language should support programmer's choice. > The original motivating example for Integer'Class was: > > Put (Obj : Integer'Class; Width : Count := 0); > > so that one didn't need to understand generic instantiations just to do > simple I/O of strongly typed entities. Yes. Cloned Integer will "inherit" this Put operation in Ada 83 sense. Ada 83 cloning is orthogonal to type hierarchies. You get a new hierarchy when you clone a type. > I don't think a version of untagged'Class that did not work on existing > derived types would fly. Astonishing that you even considered that possibility. In my view they are completely independent things. > In any case, I didn't realize that you were making an entire new kind of > type derivation To me it is exactly same as tagged extension when you add nothing to the existing representation. We also need "extension" that drops parent's representation altogether. E.g. something like: type Character is new Unsigned_8 -- or enumeration, whatever and Wide_Wide_Character'Interface; Character is member of Wide_Wide_Character'Class with a representation different from Wide_Wide_Character. >> Moreover, it is highly desired to that cloning were available for tagged >> types as well: >> >> package Original is new Ada.Containers.Vectors ...; >> type Clone is new Original.Vector; -- Cloning, not extending! >> >> Now, I have to hierarchies of Vector, not very useful in this particular >> case, because of missing helper types, but anyway. > > Pointless complication. I thought you were trying to simplify the language! Making it regular is a simplification. >>> overriding >>> procedure Op (A : in out Der; B : in Der); >> >> This is not an overriding since the mode is different. > > It *is* an overriding in Ada 83, and it still is in Ada 2012. I agree that > it should not have been, but that is irrelevant because we're stuck with it. Only when Der is derived using Ada 83 construct. Int'Class will be built using "extension." >>> Obj : Int'Class := Der'(1); >>> Op (A => 1, B => Obj); -- Legal?? >> >> MD is not fully implemented in Ada, but anyway, presuming that Op is a >> multi-method, that the mode is "in" and that 1 is Universal_Integer (is >> it?), the above is illegal because Op is not a method of >> Universal_Integer'Class. You would have to write it as: >> >> Op (A => Der'(1), B => Obj); -- Same tags >> Op (A => Int'(1), B => Obj); -- Different tags, Constraint_Error > > This seems wrong; an integer literal usually gets its type from context. > It's only a value of type Universal_Integer if there is no type given from > context (as in a type conversion or number declaration). I was presuming > that integer literals act as tag-indeterminate functions (the most sensible > model; if you have constants for a tagged type you usually would model them > as tag-indeterminate functions - for instance, the constants Zero and One in > a universal arithmetic package), you don't need multiple dispatch: the Ada > dispatching rules simply calls the correct version of the function for the > tag of the object. And that's what we would want to happen for integer > literals (that's the closest analogy to what happens for existing > expressions). This is one of possible interpretations of Ada semantics. You consider literals primitive operations, e.g. function "1" return Int; In Ada 95 such function has to be overridden, when Der extends Int. However, if the representation is inherited and not changed, the rule could be that the compiler silently overrides all literals: overriding function "1" return Der; In this case you will have 1 overloaded. Op will become ambiguous. The alternative with different types can be discarded using some preference rules, e.g. domination, and thus ambiguity resolved. >>> An interface can't have "..." as the parameter type for Write; there has >>> to be something there. >> >> procedure Write (File : in out File_Access; Data : Stream_Element_Array) >> is abstract; >> >>> And that's the target type! Say again how it is that you >>> are not exposing this type?? >> >> The target is File. I would gladly have MD and a hierarchy for the second >> parameter, but that is another story for now. > > OK, if the target is File, then you know that - that's public information. > When you dereference a File_Handle, you get a File. You don't have to make > the contents of File public, just it's name. So I still don't see why you > think this is a problem. I don't want to expose File at all. Public views should have no access to it, otherwise than indirectly through the handle. E.g. they should not be able to get an access the file object, store it somewhere, deallocate it, use stream attributes on it, and perform any other fancy stuff. Furthermore, later on, a decision may fall to replace file descriptor with something completely different keeping code that uses handles intact. It is good old information hiding principle. >> Because whether a message is relevant to the choice if the program were OK >> to deploy depends now on the message content. The language does not help >> me anymore to indicate it as a bug. > > But there is absolutely nothing new about this. There is nothing new that people die, yet nobody actually likes it. > GNAT has a variety of > warnings (calling everything it displays a "warning" in order to avoid > arguments about its particular classifications of message), but most people > choose to treat some subset of them as errors that have to be removed before > deployment. You would do that same; choose a *class* of warnings that have > to be removed; there is no parsing of messages needed. If a warning in the > prohibited class exists, the program is not ready for deployment. Some C compilers give warning when you write: if (x = 1) ... > Yes, this means you need to develop a coding standard and a development > standard to ensure that these these things are followed. But not having > those in some form is just lousy programming management. Error checks do not belong to coding standards. Coding standard, and testing, and code review etc are there when compiler checks were impossible. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-28 13:50 ` Dmitry A. Kazakov @ 2013-03-28 21:55 ` Randy Brukardt 2013-03-29 12:26 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-03-28 21:55 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:cqf0yy6q930$.1sdzw45bc0c1w.dlg@40tude.net... > On Wed, 27 Mar 2013 14:42:47 -0500, Randy Brukardt wrote: > >> The problem is that a slice ought to be a referential object as you put >> it, >> and a "regular" object is definitely *not* a referential object (a copy >> copies the data). > > What is "regular" object here? String? A non-slice string object. >> I don't see any way for a single data type to have two >> different behaviors > > These are two data types, string and slice. Are you treating slice as an > Ada-subtype of string? I consider slice a member of same class as string, > yet a distinct type (in Ada sense). This is like 4.1.5, but in the same > type hierarchy. I thought you might do that, but then you're going to have problems of compatibility (Ada currently considers them the same type). An operation like "&" cannot not allow mixed string operands (if you do allow that, you make string literals ambiguous). ... >> Nobody wants "type cloning". > > It is a very useful building block to me. Anyway it is Ada 83 legacy. Ada 83 derived types are virtually useless, and no one understood how they worked. I objected to building tagged types on that foundation during Ada 9x, but they didn't pay any attention to me on that. :-) Ada 83 derived types would be one of the first things to get rid of in a new Ada-like language -- everything should be related. Indeed, all integer types belong to Root_Integer'Class (you just can't name that type in Ada as it stands); it would be weird to *break* that. ... >> I don't think a version of untagged'Class that did not work on existing >> derived types would fly. > > Astonishing that you even considered that possibility. In my view they are > completely independent things. You really have a strange mind. The whole idea of 'Class is to allow different but related types to share implementations. You're only allowed to convert between related types, which includes derived types. >> In any case, I didn't realize that you were making an entire new kind of >> type derivation > > To me it is exactly same as tagged extension when you add nothing to the > existing representation. Sure, this I totally agree with. But those are highly related to each other: Parent'Class includes the parent and the derivation. > We also need "extension" that drops parent's representation altogether. > E.g. something like: > > type Character is new Unsigned_8 -- or enumeration, whatever > and Wide_Wide_Character'Interface; > > Character is member of Wide_Wide_Character'Class with a representation > different from Wide_Wide_Character. I don't think that would work semantically, at least in the 'Class case. Unless you expect every operation down to assigning individual components to be dispatching, even in primitive routines defined for a specific type. That's because you can't copy all tagged types (we have to have limited types), and thus calling a parent operation would have to assume that extensions have a different representation. That would both have problems of re-dispatch and simply would be awfully expensive (you'd have to do full program compilation to have any hope of decent code). The only alternative would be to totally ban implementation inheritance on such types, but as implementation inheritance is 10 times more useful than interface inheritance, it would make the construct 95% useless. >>> Moreover, it is highly desired to that cloning were available for tagged >>> types as well: >>> >>> package Original is new Ada.Containers.Vectors ...; >>> type Clone is new Original.Vector; -- Cloning, not extending! >>> >>> Now, I have to hierarchies of Vector, not very useful in this particular >>> case, because of missing helper types, but anyway. >> >> Pointless complication. I thought you were trying to simplify the >> language! > > Making it regular is a simplification. This isn't regular. All numeric types are currently members of a single hierarchy, and in practice, the vast majority of tagged types are members of two hierarchies (controlled and limited controlled). If I was going to simplify this further, I would make all of these into a single hierarchy. More hierarchies don't buy anything (you can always move your 'Classes around in the hierarchy to get subsets). >>>> overriding >>>> procedure Op (A : in out Der; B : in Der); >>> >>> This is not an overriding since the mode is different. >> >> It *is* an overriding in Ada 83, and it still is in Ada 2012. I agree >> that >> it should not have been, but that is irrelevant because we're stuck with >> it. > > Only when Der is derived using Ada 83 construct. Int'Class will be built > using "extension." No way; derived types currently form a hierarchy (that's why you can interconvert them); changing that would require fundamentally changing the Ada model of hierarchies. The issue today is that you can't name those hierarchies, that's what untagged 'Class would allow. >>>> Obj : Int'Class := Der'(1); >>>> Op (A => 1, B => Obj); -- Legal?? >>> >>> MD is not fully implemented in Ada, but anyway, presuming that Op is a >>> multi-method, that the mode is "in" and that 1 is Universal_Integer (is >>> it?), the above is illegal because Op is not a method of >>> Universal_Integer'Class. You would have to write it as: >>> >>> Op (A => Der'(1), B => Obj); -- Same tags >>> Op (A => Int'(1), B => Obj); -- Different tags, Constraint_Error >> >> This seems wrong; an integer literal usually gets its type from context. >> It's only a value of type Universal_Integer if there is no type given >> from >> context (as in a type conversion or number declaration). I was presuming >> that integer literals act as tag-indeterminate functions (the most >> sensible >> model; if you have constants for a tagged type you usually would model >> them >> as tag-indeterminate functions - for instance, the constants Zero and One >> in >> a universal arithmetic package), you don't need multiple dispatch: the >> Ada >> dispatching rules simply calls the correct version of the function for >> the >> tag of the object. And that's what we would want to happen for integer >> literals (that's the closest analogy to what happens for existing >> expressions). > > This is one of possible interpretations of Ada semantics. You consider > literals primitive operations, e.g. > > function "1" return Int; > > In Ada 95 such function has to be overridden, when Der extends Int. > However, if the representation is inherited and not changed, the rule > could > be that the compiler silently overrides all literals: > > overriding function "1" return Der; > > In this case you will have 1 overloaded. Op will become ambiguous. Yes, this is how Ada literals work today. This isn't how its described (it's an implicit conversion rather than overloading) but the effect is the same. > The alternative with different types can be discarded using some > preference > rules, e.g. domination, and thus ambiguity resolved. Preference rules cause Beaujolias effects, and almost never can be tolerated. Ada used to have some for literals and they caused all manner of problems. The preference rules for universal causes problems as well (as you are pointing out here); these are extremely fragile and only work because universal types can't have any user-defined operations or visibility changes. As soon as user-defined things are involved, preference rules simply don't work. Maybe they would work in a language without nesting and private parts and use clauses, but they don't work in Ada. (The problem being that adding or removing a single declaration can silently change the meaning of an expression without causing an error. This is considered intolerable.) >>>> An interface can't have "..." as the parameter type for Write; there >>>> has >>>> to be something there. >>> >>> procedure Write (File : in out File_Access; Data : >>> Stream_Element_Array) >>> is abstract; >>> >>>> And that's the target type! Say again how it is that you >>>> are not exposing this type?? >>> >>> The target is File. I would gladly have MD and a hierarchy for the >>> second >>> parameter, but that is another story for now. >> >> OK, if the target is File, then you know that - that's public >> information. >> When you dereference a File_Handle, you get a File. You don't have to >> make >> the contents of File public, just it's name. So I still don't see why you >> think this is a problem. > > I don't want to expose File at all. Public views should have no access to > it, otherwise than indirectly through the handle. E.g. they should not be > able to get an access the file object, store it somewhere, deallocate it, > use stream attributes on it, and perform any other fancy stuff. > Furthermore, later on, a decision may fall to replace file descriptor with > something completely different keeping code that uses handles intact. It > is > good old information hiding principle. Fine. But then you don't need any user-visible dereferencing, and you surely wouldn't use it. My contention remains: if you are going to allow user "Handle.all", then you need to expose the type of Handle.all. If you don't need to allow that, then you are not going to use 4.1.5 at all. So I fail to see your concern. >>> Because whether a message is relevant to the choice if the program were >>> OK >>> to deploy depends now on the message content. The language does not help >>> me anymore to indicate it as a bug. >> >> But there is absolutely nothing new about this. > > There is nothing new that people die, yet nobody actually likes it. > >> GNAT has a variety of >> warnings (calling everything it displays a "warning" in order to avoid >> arguments about its particular classifications of message), but most >> people >> choose to treat some subset of them as errors that have to be removed >> before >> deployment. You would do that same; choose a *class* of warnings that >> have >> to be removed; there is no parsing of messages needed. If a warning in >> the >> prohibited class exists, the program is not ready for deployment. > > Some C compilers give warning when you write: > > if (x = 1) ... > >> Yes, this means you need to develop a coding standard and a development >> standard to ensure that these these things are followed. But not having >> those in some form is just lousy programming management. > > Error checks do not belong to coding standards. Coding standard, and > testing, and code review etc are there when compiler checks were > impossible. Compiler checks are impossible for these things. Unless you want to drive yourself nuts with OOP baloney - and it's never going to be possible to do these sorts of checks with type checking. (This is not a type problem, it's a subtype (in the Ada sense) problem.) Feel free to pick your poison, as it will, but expecting types to do all of the work is just as silly as expecting that you can make a correct program with defining any types at all. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-28 21:55 ` Randy Brukardt @ 2013-03-29 12:26 ` Dmitry A. Kazakov 2013-03-30 0:49 ` Randy Brukardt 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-29 12:26 UTC (permalink / raw) On Thu, 28 Mar 2013 16:55:34 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:cqf0yy6q930$.1sdzw45bc0c1w.dlg@40tude.net... >> These are two data types, string and slice. Are you treating slice as an >> Ada-subtype of string? I consider slice a member of same class as string, >> yet a distinct type (in Ada sense). This is like 4.1.5, but in the same >> type hierarchy. > > I thought you might do that, but then you're going to have problems of > compatibility (Ada currently considers them the same type). An operation > like "&" cannot not allow mixed string operands (if you do allow that, you > make string literals ambiguous). Right, if strings form a hierarchy, then "&" must be primitive and a multi-method. There is no alternative to that. Even if you are going to add a completely new set of string types without slices you still will have this problem: declare X : New_String_Type; Y : A_Descendant_Of; begin ... X & Y ...; -- Is this legal? Does it raise Constraint_Error? The answers must be yes, no. And for this "&" must be a multi-method with all combinations of argument and the result types defined. Making some of them class-wide could reduce the number of combinations. And it will be ambiguous with literals and other overloaded operations returning string objects. >>> Nobody wants "type cloning". >> >> It is a very useful building block to me. Anyway it is Ada 83 legacy. > > Ada 83 derived types are virtually useless, and no one understood how they > worked. What would you do if you need a new type with same properties. Copy-paste? Example: type Position is <some positive number>; type Key is some <some positive number>; type Container is ...; How do you prevent Position and Key mixed in Container operations if they belong to same hierarchy? >>> I don't think a version of untagged'Class that did not work on existing >>> derived types would fly. >> >> Astonishing that you even considered that possibility. In my view they are >> completely independent things. > > You really have a strange mind. The whole idea of 'Class is to allow > different but related types to share implementations. Yes, if "implementation" means class-wide and inherited operations. The idea of T'Class is to share an interface, so that programs could be written in terms of the interface, which would make them working on all instances of the class (AKA, generic programming). We want to have this for all types including those which representations are different. If you want to be able to inherit an operation for such a type, the only way to do it is to compose old body with type representation conversion. This is the model for untagged classes. You will be free to derive from any non-limited type ignoring its representation, but then the compiler will ask you either to override an inherited primitive operation or else define corresponding conversions so that it could create one. > You're only allowed to > convert between related types, which includes derived types. That is the only way to have a class without sharing (inheriting, actually) representations. The model of Ada 95 tagged types provides a class with shared representations. This need to be augmented for the case when representations has to be different. Note that this was partially done when Java interfaces were added in Ada 2005. Java interface is a type without any representation, so there is nothing to inherit from, except for a slot for the type tag. Drop that slot, and you will have a workable model for building classes of scalar types and arrays. >> We also need "extension" that drops parent's representation altogether. >> E.g. something like: >> >> type Character is new Unsigned_8 -- or enumeration, whatever >> and Wide_Wide_Character'Interface; >> >> Character is member of Wide_Wide_Character'Class with a representation >> different from Wide_Wide_Character. > > I don't think that would work semantically, at least in the 'Class case. > Unless you expect every operation down to assigning individual components to > be dispatching, even in primitive routines defined for a specific type. Exactly! I want all that mess to become orderly defined primitive operations. This also includes attributes and aspects. There should be no special cases like T'Read, ":=" etc. There should be no magic and strange stuff like attributes, slices, ranges, aspects infesting the language, only objects and operations. > That's because you can't copy all tagged types (we have to have limited > types), and thus calling a parent operation would have to assume that > extensions have a different representation. That would both have problems of > re-dispatch and simply would be awfully expensive (you'd have to do full > program compilation to have any hope of decent code). Re-dispatch is a bad idea anyway. Yes, for untagged classes the conversions from the specific type to a class and backwards are no more for free. But these types are meant to be copyable anyway. > The only alternative would be to totally ban implementation inheritance on > such types, but as implementation inheritance is 10 times more useful than > interface inheritance, it would make the construct 95% useless. Huh, and you tell me that type cloning is useless? Cloning is all about implementation inheritance. For copyable objects implementation inheritance is much less interesting than for by-reference types. Operations (especially cross operations) need to be re-implemented anyway, at least for performance reasons. Few other operations are [conversion ->] inherited body [-> conversion]. >> Making it regular is a simplification. > > This isn't regular. All numeric types are currently members of a single > hierarchy, It is not a single hierarchy. It is a forest of similar hierarchies. They are similar just because they were constructed by the compiler rather than by the programmer. It is nominal vs. structured. Same structure does not imply equality, at least, it is meant to be so in Ada. > and in practice, the vast majority of tagged types are members of > two hierarchies (controlled and limited controlled). So what? This is equivalent to say that a type can be either copyable or else not. Yes, "copyable" is an interface. There is a countable infinity of other interfaces a type may implement. Which is why multiple inheritance is so important. But even if two types implement the same interface, e.g. can be copied, that by no means should automatically imply that these types must belong to the same hierarchy. This decision is up to the programmer. Type cloning is a valuable mechanism to insulate type hierarchies against each other. Consider a container type defined for Copyable'Class. How do you prevent mixing apples and oranges in there? Creating two new container types for copyable apples and copyable oranges? But they are still the same hierarchy. You need some fundamental operation which tells that a type breaks off the hierarchy. > More hierarchies don't buy anything (you can always move your 'Classes > around in the hierarchy to get subsets). They buy safety through type checks. >>>>> overriding >>>>> procedure Op (A : in out Der; B : in Der); >>>> >>>> This is not an overriding since the mode is different. >>> >>> It *is* an overriding in Ada 83, and it still is in Ada 2012. I agree that >>> it should not have been, but that is irrelevant because we're stuck with >>> it. >> >> Only when Der is derived using Ada 83 construct. Int'Class will be built >> using "extension." > > No way; derived types currently form a hierarchy (that's why you can > interconvert them); changing that would require fundamentally changing the > Ada model of hierarchies. To me it is a wording issue not a real problem. If you want a theoretic POV, no problem, both notions are fully compatible with each other, it is one in a more general model: Ada 83 hierarchy is a class of equivalence. Types from the hierarchy are equal in the sense that they can be used interchangeable in the operations. Each type is both a sub- and supertype of another (in non-Ada sense). The graph of types is undirected. Ada 95 tagged hierarchies are rather directed. A tagged type is only a subtype (in non-Ada sense) of another tagged type in the hierarchy. Untagged class would be an ability to have directed hierarchies of scalar types and arrays. Why there should be none? Conversely, ad-hoc supertypes would allow building Ada 83 equivalent types with all types including tagged. You would derive a new type [=subtype] and simultaneously declare it a supertype. This will effectively become a type you can use interchangeably with the parent type [and get some ambiguities, surely]. > The issue today is that you can't name those > hierarchies, that's what untagged 'Class would allow. Name it a "taxonomy" then. >>>>> Obj : Int'Class := Der'(1); >>>>> Op (A => 1, B => Obj); -- Legal?? >>>> >>>> MD is not fully implemented in Ada, but anyway, presuming that Op is a >>>> multi-method, that the mode is "in" and that 1 is Universal_Integer (is >>>> it?), the above is illegal because Op is not a method of >>>> Universal_Integer'Class. You would have to write it as: >>>> >>>> Op (A => Der'(1), B => Obj); -- Same tags >>>> Op (A => Int'(1), B => Obj); -- Different tags, Constraint_Error >>> >>> This seems wrong; an integer literal usually gets its type from context. >>> It's only a value of type Universal_Integer if there is no type given from >>> context (as in a type conversion or number declaration). I was presuming >>> that integer literals act as tag-indeterminate functions (the most sensible >>> model; if you have constants for a tagged type you usually would model them >>> as tag-indeterminate functions - for instance, the constants Zero and One in >>> a universal arithmetic package), you don't need multiple dispatch: the Ada >>> dispatching rules simply calls the correct version of the function for the >>> tag of the object. And that's what we would want to happen for integer >>> literals (that's the closest analogy to what happens for existing >>> expressions). >> >> This is one of possible interpretations of Ada semantics. You consider >> literals primitive operations, e.g. >> >> function "1" return Int; >> >> In Ada 95 such function has to be overridden, when Der extends Int. >> However, if the representation is inherited and not changed, the rule >> could be that the compiler silently overrides all literals: >> >> overriding function "1" return Der; >> >> In this case you will have 1 overloaded. Op will become ambiguous. > > Yes, this is how Ada literals work today. This isn't how its described (it's > an implicit conversion rather than overloading) but the effect is the same. > >> The alternative with different types can be discarded using some >> preference rules, e.g. domination, and thus ambiguity resolved. > > Preference rules cause Beaujolias effects, and almost never can be > tolerated. The idea that you can have an object of partially visible type was likely wrong. So the separation of "with" and "use" was an mistake too. The language should rather prevent declarations which are doomed to cause ambiguities later. > As soon as user-defined things are involved, preference rules simply don't > work. Some rules are clearly needed to choose between: function "&" (Left : String; Right : Wide_String) return Wide_String; function "&" (Left : String; Right : Wide_String) return String; The problem is not Ada design, but the nature of multi-methods with cross operations enabled. The programmer should be allowed to declare some signatures as equivalent, meaning: the compiler is free to use any without reporting ambiguity. The principle is always same, if you cannot decide it, leave to choice to the programmer. > The problem being that adding > or removing a single declaration can silently change the meaning of an > expression without causing an error. This is considered intolerable.) Not always. It is OK with overriding. My take on this that the language should prevent situations when you have an object with some of its operations invisible, especially, when these operations override the same primitive operation. I think this should be possible to do while keeping it backward compatible, because standard types are always visible anyway. > My contention remains: if you are going to allow user > "Handle.all", then you need to expose the type of Handle.all. If you don't > need to allow that, then you are not going to use 4.1.5 at all. So I fail to > see your concern. I don't need Handle.all, but I do need Handle.Foo meaning Handle.all.Foo. Publicly it is an opaque by-copy type, privately it is an access type. > Compiler checks are impossible for these things. Why so? How is it different from in-mode of an argument. The compiler routinely checks that you never update it. > Unless you want to drive > yourself nuts with OOP baloney - and it's never going to be possible to do > these sorts of checks with type checking. I don't understand why it has to be impossible to have: type File is ...; type Read_File is new File ...; prcodure Read (X : in out File; Data : out Stream_Element_Array); type Write_File is new File ...; procedure Write (X : in out File; Data : Stream_Element_Array); type Readwrite_File is new Read_File and Write_File ...; with concrete types, but well possible with interfaces. The nature of the check that the operation Write is not applied to Read_File is exactly same in both cases. It is not about checking, especially because the above construct is still possible to get through generics. It is just a stupid limitation motivated by urban legends mindlessly repeated through (using you wording) OO-baloney texts. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-29 12:26 ` Dmitry A. Kazakov @ 2013-03-30 0:49 ` Randy Brukardt 2013-03-30 2:55 ` Shark8 2013-03-30 9:20 ` Is this expected behavior or not Dmitry A. Kazakov 0 siblings, 2 replies; 242+ messages in thread From: Randy Brukardt @ 2013-03-30 0:49 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:byacn0wck9qt$.norrlukaw80l$.dlg@40tude.net... > On Thu, 28 Mar 2013 16:55:34 -0500, Randy Brukardt wrote: > >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >> news:cqf0yy6q930$.1sdzw45bc0c1w.dlg@40tude.net... > >>> These are two data types, string and slice. Are you treating slice as an >>> Ada-subtype of string? I consider slice a member of same class as >>> string, >>> yet a distinct type (in Ada sense). This is like 4.1.5, but in the same >>> type hierarchy. >> >> I thought you might do that, but then you're going to have problems of >> compatibility (Ada currently considers them the same type). An operation >> like "&" cannot not allow mixed string operands (if you do allow that, >> you >> make string literals ambiguous). > > Right, if strings form a hierarchy, then "&" must be primitive and a > multi-method. There is no alternative to that. Even if you are going to > add > a completely new set of string types without slices you still will have > this problem: > > declare > X : New_String_Type; > Y : A_Descendant_Of; > begin > ... X & Y ...; -- Is this legal? Does it raise Constraint_Error? > > The answers must be yes, no. And for this "&" must be a multi-method with > all combinations of argument and the result types defined. Making some of > them class-wide could reduce the number of combinations. And it will be > ambiguous with literals and other overloaded operations returning string > objects. Well, actually, the answer is "no, irrelevant" as it is for the existing Ada types. You can always use an explicit type conversion if you need these to match. If each type effectively has its own literals, then this works perfectly. Mixing types is precisely the sort of thing you don't want to do in a strong typing environment. I think this problem illustrates why the schemes you are thinking of will never be used -- they just add far too much complexity to the language. Maybe the 10000 foot view is simpler, but the complexity under the hood would be extremely difficult to implement. >>>> Nobody wants "type cloning". >>> >>> It is a very useful building block to me. Anyway it is Ada 83 legacy. >> >> Ada 83 derived types are virtually useless, and no one understood how >> they >> worked. > > What would you do if you need a new type with same properties. Copy-paste? Make a new declaration, using constants for the properties. But the real answer is that this never happens, so it's a bogus concern. If the properties are truly the same, it's hardly likely that the type is the same. After all, the maximum number of Apples and Oranges is unlikely to be the same (the physical properties differ). > Example: > > type Position is <some positive number>; > type Key is some <some positive number>; > type Container is ...; > > How do you prevent Position and Key mixed in Container operations if they > belong to same hierarchy? If the container operations take parameters of type Key, then you can only pass a Position to such a parameter if you use an explicit conversion. That's how it works in Ada today - there's no automatic conversion between different specific types. If you have Root_Integer'Class parameters, then you made a choice to have weak typing, so there is no problem. I think you're overthinking this... ... > The model of Ada 95 tagged types provides a class with shared > representations. This need to be augmented for the case when > representations has to be different. Note that this was partially done > when > Java interfaces were added in Ada 2005. Java interface is a type without > any representation, so there is nothing to inherit from, except for a slot > for the type tag. Drop that slot, and you will have a workable model for > building classes of scalar types and arrays. I don't know how one could implement "interfaces" without a tag. And there is no requirement in Ada that the representations of the tag be the same (although an implementation can impose one since there is no requirements about supporting tag positions). >>> We also need "extension" that drops parent's representation altogether. >>> E.g. something like: >>> >>> type Character is new Unsigned_8 -- or enumeration, whatever >>> and Wide_Wide_Character'Interface; >>> >>> Character is member of Wide_Wide_Character'Class with a representation >>> different from Wide_Wide_Character. >> >> I don't think that would work semantically, at least in the 'Class case. >> Unless you expect every operation down to assigning individual components >> to >> be dispatching, even in primitive routines defined for a specific type. > > Exactly! I want all that mess to become orderly defined primitive > operations. This also includes attributes and aspects. There should be no > special cases like T'Read, ":=" etc. There should be no magic and strange > stuff like attributes, slices, ranges, aspects infesting the language, > only > objects and operations. You miss my point: the effect is to make *every* operation in *every* subprogram -- including specific ones -- dispatching -- which would be way too expensive in practice (no optimization would be possible). >> That's because you can't copy all tagged types (we have to have limited >> types), and thus calling a parent operation would have to assume that >> extensions have a different representation. That would both have problems >> of >> re-dispatch and simply would be awfully expensive (you'd have to do full >> program compilation to have any hope of decent code). > > Re-dispatch is a bad idea anyway. > > Yes, for untagged classes the conversions from the specific type to a > class > and backwards are no more for free. But these types are meant to be > copyable anyway. You are still misunderstanding. You'd *have* to have redispatch because the only way to implement inheritance would be to make all operations (even those very low-level ones) dispatching in *all* instances. There could be no statically bound operations. >> The only alternative would be to totally ban implementation inheritance >> on >> such types, but as implementation inheritance is 10 times more useful >> than >> interface inheritance, it would make the construct 95% useless. > > Huh, and you tell me that type cloning is useless? Cloning is all about > implementation inheritance. The only useful inheritance is implementation inheritance, but it requires all of the types to be in the same hierarchy so that they can be interconvertable. (That doesn't necessarily mean *cheaply* interconvertable.) Interfaces are useful only in a very small % of cases, and that is such a small % that I wouldn't bother at all (certainly not more than Ada 95 abstract types). > For copyable objects implementation inheritance is much less interesting > than for by-reference types. Operations (especially cross operations) need > to be re-implemented anyway, at least for performance reasons. Few other > operations are [conversion ->] inherited body [-> conversion]. Not all objects that have different representations are copyable. (Consider an array of some_task'class). Whatever solution one has for untagged types has to be able to deal with uncopyable objects with different representations. But banning implementation inheritance makes the whole thing useless IMHO, and supporting it is too expensive. It really kills the entire idea. >>> Making it regular is a simplification. >> >> This isn't regular. All numeric types are currently members of a single >> hierarchy, > > It is not a single hierarchy. It is a forest of similar hierarchies. They > are similar just because they were constructed by the compiler rather than > by the programmer. It is nominal vs. structured. Same structure does not > imply equality, at least, it is meant to be so in Ada. No, you need to read the RM again. All integer types are effectively derived from Universal_Integer, and all of the rest are derived from Universal_Real. There are only two hierachies. You're just not allowed to name them, which is limiting in various ways (especially as you can use 'Pos to force run-time operations to occur for Universal_Integer). >> and in practice, the vast majority of tagged types are members of >> two hierarchies (controlled and limited controlled). > > So what? This is equivalent to say that a type can be either copyable or > else not. Yes, "copyable" is an interface. There is a countable infinity > of > other interfaces a type may implement. Which is why multiple inheritance > is > so important. You mean why it is so useless. If you break down every possible property of a type as an interface, you'll end up with a very expensive complex structure. The only way I know of to implement multiple inheritance is with a linked-list of tags, which isn't too bad when only a few interfaces are involved. But once you get the dozens you're talking about, it's going to cause a very significant overhead. > But even if two types implement the same interface, e.g. can be copied, > that by no means should automatically imply that these types must belong > to > the same hierarchy. This decision is up to the programmer. I suspect that *all* types should belong to the same hierarchy, if you are going this OOP route. Because you need operations that work on every object, copyable or not. Remember, there are no type conversions between types in different hierarchies. > Type cloning is a valuable mechanism to insulate type hierarchies against > each other. > > Consider a container type defined for Copyable'Class. How do you prevent > mixing apples and oranges in there? Creating two new container types for > copyable apples and copyable oranges? Of course you have separate containers for each kind of thing that they contain. When you define a container for Copyable'Class, you are allowing anything non-limited in that container -- you've specifically decided not to enforce any sort of checking on the contents. > But they are still the same > hierarchy. You need some fundamental operation which tells that a type > breaks off the hierarchy. Yes, of course all containers ought to be members of the same hierarchy. How else would you create generic algorithms? It's unfortunate that Ada doesn't allow this because the element type makes it impossible. No idea how to work around that. >> More hierarchies don't buy anything (you can always move your 'Classes >> around in the hierarchy to get subsets). > > They buy safety through type checks. Since *every* type in a hierarchy is different and cannot be mixed with any other type unless you explicitly request it (via declaring something to be class-wide), you are gaining absolutely nothing by added hierarchies. ... >> The issue today is that you can't name those >> hierarchies, that's what untagged 'Class would allow. > > Name it a "taxonomy" then. I see, you're wasting my time again by changing the terminology on the fly. I should know better than to discuss anything substantive with you. My mistake. ... >> Preference rules cause Beaujolias effects, and almost never can be >> tolerated. > > The idea that you can have an object of partially visible type was likely > wrong. So the separation of "with" and "use" was an mistake too. The > language should rather prevent declarations which are doomed to cause > ambiguities later. No one has ever figured out how to do that, and in any case, it would be incompatible with Ada as it stands. We can't even do simple things like make objects overloadable because of compatibility concerns -- changing the visibility model is a non-starter. >> As soon as user-defined things are involved, preference rules simply >> don't >> work. > > Some rules are clearly needed to choose between: > > function "&" (Left : String; Right : Wide_String) return Wide_String; > function "&" (Left : String; Right : Wide_String) return String; There are no such operations predefined in Ada, and that's because you *can't* chose between them. You can of course declare them yourself (that's essentially what happens in Ada.Strings.Unbounded), but the net effect is that you then cannot use literals with such a type. Ada does not attempt to prevent you from shooting yourself in the head. :-) >> The problem being that adding >> or removing a single declaration can silently change the meaning of an >> expression without causing an error. This is considered intolerable.) > > Not always. It is OK with overriding. That isn't quite the same thing, because the declaration in question is replacing one, not adding or removing one. And of course in a good system they'll also have the same preconditions and postconditions, meaning that the changed operation would have very similar semantics. The cases I'm thinking about have to do with ordinary object declarations being added or removed elsewhere in the program. Changing the object used silently is intolerable. Personally, however, I've concluded that the OOP cases are also very dangerous. Maybe not quite to the level of "intolerable", but pretty close. That's the curse of OOP: not being able to figure out what routine is being called (and especially why the *wrong* routine is being called). > My take on this that the language should prevent situations when you have > an object with some of its operations invisible, especially, when these > operations override the same primitive operation. I think this should be > possible to do while keeping it backward compatible, because standard > types > are always visible anyway. Huh? This is very common with private types. With interfaces, we enforced such a rule and it is rather limiting. Claw uses hidden operations on window objects to keep the mechanisms of the message loop hidden away. Otherwise, we'd have no way to ensure that our objects are getting the messages as intended, and it would be impossible to make anything work reliably. These routines have to be dispatching, as the responses to different messages obviously depend on the kind of object they are associated with. So they have to be inherited and overriddable, but not changable by clients (who might be doing their own overriding of public operations for their own purposes). In general, designers of good libraries need to be able to hide the mechanics of the implementation from clients (both for understandability and to prevent people from screwing them up). Without being able to hide operations, there is no hope of that. >> My contention remains: if you are going to allow user >> "Handle.all", then you need to expose the type of Handle.all. If you >> don't >> need to allow that, then you are not going to use 4.1.5 at all. So I fail >> to >> see your concern. > > I don't need Handle.all, but I do need Handle.Foo meaning Handle.all.Foo. > Publicly it is an opaque by-copy type, privately it is an access type. In this case, you're probably not using 4.1.5, because it is only about .all (and writing into .all specifically). If you are using 4.1.5 (to allow writing into Foo), you're exposing an access to the type of Foo, not to the file type. >> Unless you want to drive >> yourself nuts with OOP baloney - and it's never going to be possible to >> do >> these sorts of checks with type checking. > > I don't understand why it has to be impossible to have: > > type File is ...; > > type Read_File is new File ...; > prcodure Read (X : in out File; Data : out Stream_Element_Array); > > type Write_File is new File ...; > procedure Write (X : in out File; Data : Stream_Element_Array); > > type Readwrite_File is new Read_File and Write_File ...; > > with concrete types, but well possible with interfaces. > > The nature of the check that the operation Write is not applied to > Read_File is exactly same in both cases. You can do this sort of thing in exceedingly simple cases. But it simply gets too complex the more properties that you try to decompose on. And every such property is making all of your dispatching calls slower and slower. Moreover, most interesting properties are not binary like the file mode. They tend to depend on the *values* of parameters, and often on combinations of values. It just is too complex to do. > It is not about checking, especially because the above construct is still > possible to get through generics. It is just a stupid limitation motivated > by urban legends mindlessly repeated through (using you wording) > OO-baloney > texts. Implementability is hardly an "urban legend". If the resulting code is too slow to use, then it's pretty silly to structure it that way, even if it is theoretically possible. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-30 0:49 ` Randy Brukardt @ 2013-03-30 2:55 ` Shark8 2013-04-01 23:43 ` Messaging question [was: Is this expected behavior or not] Randy Brukardt 2013-03-30 9:20 ` Is this expected behavior or not Dmitry A. Kazakov 1 sibling, 1 reply; 242+ messages in thread From: Shark8 @ 2013-03-30 2:55 UTC (permalink / raw) On Friday, March 29, 2013 6:49:25 PM UTC-6, Randy Brukardt wrote: > > > Claw uses hidden operations on window objects to keep the mechanisms of the > message loop hidden away. Very tangentially on this; what do you see would be the consequence of a system using a loop over a select [for messaging] -- or would it be any different? I'm really fuzzy on my low-level windows programming and, after reading this ( http://forums.codeguru.com/showthread.php?449338-Windows-message-loop-efficiency ), I found myself wondering; since you wrote CLAW I thought I'd ask. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Messaging question [was: Is this expected behavior or not] 2013-03-30 2:55 ` Shark8 @ 2013-04-01 23:43 ` Randy Brukardt 0 siblings, 0 replies; 242+ messages in thread From: Randy Brukardt @ 2013-04-01 23:43 UTC (permalink / raw) "Shark8" <onewingedshark@gmail.com> wrote in message news:09f2e5f7-84fe-419b-b27d-207e697c8e46@googlegroups.com... > On Friday, March 29, 2013 6:49:25 PM UTC-6, Randy Brukardt wrote: >> >> >> Claw uses hidden operations on window objects to keep the mechanisms of >> the >> message loop hidden away. > > Very tangentially on this; what do you see would be the consequence of a > system > using a loop over a select [for messaging] -- or would it be any > different? > > I'm really fuzzy on my low-level windows programming and, after reading > this >( >http://forums.codeguru.com/showthread.php?449338-Windows-message-loop-efficiency ) >, >I found myself wondering; since you wrote CLAW I thought I'd ask. The reason we hid the loop had to do with correctness more than efficiency. When you explicitly allow fooling with all of that loop mechanism, it's impossible to build anything on top of it and have any hope that it works right, because you're relying on the client to use the object exactly the right way, or it won't work (nor will it give any indication of what you did wrong). In any case, there is *always* a loop inside the application; the question in the thread mentioned above is how the loop is written. You get dozens of messages for typical actions in an Windows program; you need a loop to process them all. I believe we did our waiting at the Ada level, rather than the Windows level, because that prevented locking up the Windows program/thread while waiting for something to happen. We use Ada delays to release the CPU if we don't have anything to do (that way, the Ada runtime knows about the blocking and can schedule other work if appropriate). Again, performance had nothing to do with it, we didn't want to assume a particular Ada runtime model (that is, how tasks are mapped to threads). We tuned the performance after making these choices. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-30 0:49 ` Randy Brukardt 2013-03-30 2:55 ` Shark8 @ 2013-03-30 9:20 ` Dmitry A. Kazakov 2013-04-02 0:40 ` Randy Brukardt 1 sibling, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-30 9:20 UTC (permalink / raw) On Fri, 29 Mar 2013 19:49:25 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:byacn0wck9qt$.norrlukaw80l$.dlg@40tude.net... >> On Thu, 28 Mar 2013 16:55:34 -0500, Randy Brukardt wrote: >> >>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >>> news:cqf0yy6q930$.1sdzw45bc0c1w.dlg@40tude.net... >> >>>> These are two data types, string and slice. Are you treating slice as an >>>> Ada-subtype of string? I consider slice a member of same class as string, >>>> yet a distinct type (in Ada sense). This is like 4.1.5, but in the same >>>> type hierarchy. >>> >>> I thought you might do that, but then you're going to have problems of >>> compatibility (Ada currently considers them the same type). An operation >>> like "&" cannot not allow mixed string operands (if you do allow that, >>> you make string literals ambiguous). >> >> Right, if strings form a hierarchy, then "&" must be primitive and a >> multi-method. There is no alternative to that. Even if you are going to >> add a completely new set of string types without slices you still will have >> this problem: >> >> declare >> X : New_String_Type; >> Y : A_Descendant_Of; >> begin >> ... X & Y ...; -- Is this legal? Does it raise Constraint_Error? >> >> The answers must be yes, no. And for this "&" must be a multi-method with >> all combinations of argument and the result types defined. Making some of >> them class-wide could reduce the number of combinations. And it will be >> ambiguous with literals and other overloaded operations returning string >> objects. > > Well, actually, the answer is "no, irrelevant" as it is for the existing Ada > types. You can always use an explicit type conversion if you need these to > match. If each type effectively has its own literals, then this works > perfectly. Mixing types is precisely the sort of thing you don't want to do > in a strong typing environment. > > I think this problem illustrates why the schemes you are thinking of will > never be used -- they just add far too much complexity to the language. The point is that whether you create a totally new string hierarchy or create one for already existing string types, you will have the issue with "&" (and any other operation with more than one argument/result of string type). That is *independent* on whatever Ada did or not before. It is in the nature of a multi-method, which "&" is. If you want a hierarchy of strings you *must* face this problem. >>>>> Nobody wants "type cloning". >>>> >>>> It is a very useful building block to me. Anyway it is Ada 83 legacy. >>> >>> Ada 83 derived types are virtually useless, and no one understood how >>> they worked. >> >> What would you do if you need a new type with same properties. Copy-paste? > > Make a new declaration, using constants for the properties. Properties are operations here. > But the real > answer is that this never happens, so it's a bogus concern. If the > properties are truly the same, it's hardly likely that the type is the same. type Velocity is new Float; >> Example: >> >> type Position is <some positive number>; >> type Key is some <some positive number>; >> type Container is ...; >> >> How do you prevent Position and Key mixed in Container operations if they >> belong to same hierarchy? > > If the container operations take parameters of type Key, then you can only > pass a Position to such a parameter if you use an explicit conversion. Position and Key are just same type according to you. You said you don't need independent hierarchies of any types, which should include numbers. >> The model of Ada 95 tagged types provides a class with shared >> representations. This need to be augmented for the case when >> representations has to be different. Note that this was partially done when >> Java interfaces were added in Ada 2005. Java interface is a type without >> any representation, so there is nothing to inherit from, except for a slot >> for the type tag. Drop that slot, and you will have a workable model for >> building classes of scalar types and arrays. > > I don't know how one could implement "interfaces" without a tag. You have the tag in the representation of untagged'Class. You don't have it in the representation of untagged. >>>> We also need "extension" that drops parent's representation altogether. >>>> E.g. something like: >>>> >>>> type Character is new Unsigned_8 -- or enumeration, whatever >>>> and Wide_Wide_Character'Interface; >>>> >>>> Character is member of Wide_Wide_Character'Class with a representation >>>> different from Wide_Wide_Character. >>> >>> I don't think that would work semantically, at least in the 'Class case. >>> Unless you expect every operation down to assigning individual components >>> to be dispatching, even in primitive routines defined for a specific type. >> >> Exactly! I want all that mess to become orderly defined primitive >> operations. This also includes attributes and aspects. There should be no >> special cases like T'Read, ":=" etc. There should be no magic and strange >> stuff like attributes, slices, ranges, aspects infesting the language, >> only objects and operations. > > You miss my point: the effect is to make *every* operation in *every* > subprogram -- including specific ones -- dispatching -- which would be way > too expensive in practice (no optimization would be possible). Then it is wrong what you wrote. There will be no dispatch on specific types. (I don't understand why you think that dispatching on specific types is necessary) > You are still misunderstanding. You'd *have* to have redispatch because the > only way to implement inheritance would be to make all operations (even > those very low-level ones) dispatching in *all* instances. There could be no > statically bound operations. Yes, I still do not understand what has re-dispatch to do with inheritance (of what?) The representation is NOT inherited Primitive operations (AKA, interface) are inherited in the way standard to tagged types. That is, a NEW operation is declared with the same name and the profile where the parent type is replaced by the descendant type. The way its body is generated out of old body with parent type converted to the descendant type in- and/or out. How this requires re-dispatch? >> For copyable objects implementation inheritance is much less interesting >> than for by-reference types. Operations (especially cross operations) need >> to be re-implemented anyway, at least for performance reasons. Few other >> operations are [conversion ->] inherited body [-> conversion]. > > Not all objects that have different representations are copyable. (Consider > an array of some_task'class). Whatever solution one has for untagged types > has to be able to deal with uncopyable objects with different > representations. > > But banning implementation inheritance makes the whole thing useless IMHO, > and supporting it is too expensive. I don't ban inheritance of the representation. I want to be able not to do it when I don't need it, e.g. for character and string types. > It really kills the entire idea. No, IF String inherited the representation of Wide_Wide_String, THAT would kill the idea. The whole idea is not to inherit irrelevant representations! >>>> Making it regular is a simplification. >>> >>> This isn't regular. All numeric types are currently members of a single >>> hierarchy, >> >> It is not a single hierarchy. It is a forest of similar hierarchies. They >> are similar just because they were constructed by the compiler rather than >> by the programmer. It is nominal vs. structured. Same structure does not >> imply equality, at least, it is meant to be so in Ada. > > No, you need to read the RM again. All integer types are effectively derived > from Universal_Integer, and all of the rest are derived from Universal_Real. > There are only two hierachies. OK, this again becomes a scholastic discussion we need not to go into. The bottom line is, I regard Ada 83 construct "type S is new T;" as very useful, and wished it be valid with all specific types without silly exceptions Ada 95 made for tagged types. >>> and in practice, the vast majority of tagged types are members of >>> two hierarchies (controlled and limited controlled). >> >> So what? This is equivalent to say that a type can be either copyable or >> else not. Yes, "copyable" is an interface. There is a countable infinity of >> other interfaces a type may implement. Which is why multiple inheritance >> is so important. > > You mean why it is so useless. If you break down every possible property of > a type as an interface, you'll end up with a very expensive complex > structure. It is how it is. A number is a field, additive group, weak ordered and so on... A good language shall support programmer in expressing concepts of the problem domain. > The only way I know of to implement multiple inheritance is with > a linked-list of tags, which isn't too bad when only a few interfaces are > involved. But once you get the dozens you're talking about, it's going to > cause a very significant overhead. There is no overhead on any existing Ada program. >> But even if two types implement the same interface, e.g. can be copied, >> that by no means should automatically imply that these types must belong >> to the same hierarchy. This decision is up to the programmer. > > I suspect that *all* types should belong to the same hierarchy, if you are > going this OOP route. To make yet another bogus OOPL out of Ada? > Because you need operations that work on every object, > copyable or not. Remember, there are no type conversions between types in > different hierarchies. And, this is what different hierarchies are for. >> Type cloning is a valuable mechanism to insulate type hierarchies against >> each other. >> >> Consider a container type defined for Copyable'Class. How do you prevent >> mixing apples and oranges in there? Creating two new container types for >> copyable apples and copyable oranges? > > Of course you have separate containers for each kind of thing that they > contain. When you define a container for Copyable'Class, you are allowing > anything non-limited in that container -- you've specifically decided not to > enforce any sort of checking on the contents. And cloning is there to enforce checking. >> But they are still the same >> hierarchy. You need some fundamental operation which tells that a type >> breaks off the hierarchy. > > Yes, of course all containers ought to be members of the same hierarchy. How > else would you create generic algorithms? Easily. Cloning borrows all operations. Define algorithm on the original type. Then clone it. Done! >>> As soon as user-defined things are involved, preference rules simply >>> don't work. >> >> Some rules are clearly needed to choose between: >> >> function "&" (Left : String; Right : Wide_String) return Wide_String; >> function "&" (Left : String; Right : Wide_String) return String; > > There are no such operations predefined in Ada, and that's because you > *can't* chose between them. You can of course declare them yourself (that's > essentially what happens in Ada.Strings.Unbounded), but the net effect is > that you then cannot use literals with such a type. Ada does not attempt to > prevent you from shooting yourself in the head. :-) Are you seriously going to propose a string class without "&"? >> My take on this that the language should prevent situations when you have >> an object with some of its operations invisible, especially, when these >> operations override the same primitive operation. I think this should be >> possible to do while keeping it backward compatible, because standard >> types are always visible anyway. > > Huh? This is very common with private types. With interfaces, we enforced > such a rule and it is rather limiting. > > Claw uses hidden operations on window objects to keep the mechanisms of the > message loop hidden away. I didn't meant that. Whether public or private an operation on the object should be visible if you would see it otherwise, e.g. through use-clause. >>> My contention remains: if you are going to allow user >>> "Handle.all", then you need to expose the type of Handle.all. If you don't >>> need to allow that, then you are not going to use 4.1.5 at all. So I fail >>> to see your concern. >> >> I don't need Handle.all, but I do need Handle.Foo meaning Handle.all.Foo. >> Publicly it is an opaque by-copy type, privately it is an access type. > > In this case, you're probably not using 4.1.5, because it is only about .all > (and writing into .all specifically). Yes, 4.1.5 is a hack for one specific case. >>> Unless you want to drive >>> yourself nuts with OOP baloney - and it's never going to be possible to >>> do these sorts of checks with type checking. >> >> I don't understand why it has to be impossible to have: >> >> type File is ...; >> >> type Read_File is new File ...; >> prcodure Read (X : in out File; Data : out Stream_Element_Array); >> >> type Write_File is new File ...; >> procedure Write (X : in out File; Data : Stream_Element_Array); >> >> type Readwrite_File is new Read_File and Write_File ...; >> >> with concrete types, but well possible with interfaces. >> >> The nature of the check that the operation Write is not applied to >> Read_File is exactly same in both cases. > > You can do this sort of thing in exceedingly simple cases. But it simply > gets too complex the more properties that you try to decompose on. And every > such property is making all of your dispatching calls slower and slower. I would gladly buy that in exchange for how it is now: 100+ generic packages, 1000+ instances, 4 hours compilation time, no way to compile on a 32-bit host. > Moreover, most interesting properties are not binary like the file mode. > They tend to depend on the *values* of parameters, and often on combinations > of values. It just is too complex to do. It is becomes increasingly expensive not to do it. There is a language damage as well inflicted by all hacks of Ada 2005-2012. Further hacks are in the pipe line, I guess. >> It is not about checking, especially because the above construct is still >> possible to get through generics. It is just a stupid limitation motivated >> by urban legends mindlessly repeated through (using you wording) >> OO-baloney >> texts. > > Implementability is hardly an "urban legend". If the resulting code is too > slow to use I saw no significant overhead in C++ programs, which has full MI from the start. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-30 9:20 ` Is this expected behavior or not Dmitry A. Kazakov @ 2013-04-02 0:40 ` Randy Brukardt 2013-04-02 8:44 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-04-02 0:40 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:1gnmajx2fdjju.1bo28xwmzt1nr.dlg@40tude.net... .... > The point is that whether you create a totally new string hierarchy or > create one for already existing string types, you will have the issue with > "&" (and any other operation with more than one argument/result of string > type). That is *independent* on whatever Ada did or not before. It is in > the nature of a multi-method, which "&" is. If you want a hierarchy of > strings you *must* face this problem. No you don't. There are no language-defined multi-methods. String & String = String is not a multi-method. You, the user, can define such operations, of course, but then you have the deal with the consequences. Generally, it's best if you don't do that. ... >> If the container operations take parameters of type Key, then you can >> only >> pass a Position to such a parameter if you use an explicit conversion. > > Position and Key are just same type according to you. You said you don't > need independent hierarchies of any types, which should include numbers. You're not making any sense. We're talking about hierarchies of types; *everything* in such a hierarchy is a separate type. (Ada subtypes are completely independent of any type hierarchies, and completely irrelevant for this purpose.) There really is only one hierarchy of types per programming language; the only question is how much interoperation between different types is allowed. It's probably misleading to ever say that there is "more than one hierarchy of types" in a program (or programming language). My guess is that you've redefined the meaning of hierarchy again, so please just forget it, there's no point in discussing this further. If you're unwilling to use Ada terminology on this Ada list, then we really have nothing to talk about. >>> The model of Ada 95 tagged types provides a class with shared >>> representations. This need to be augmented for the case when >>> representations has to be different. Note that this was partially done >>> when >>> Java interfaces were added in Ada 2005. Java interface is a type without >>> any representation, so there is nothing to inherit from, except for a >>> slot >>> for the type tag. Drop that slot, and you will have a workable model for >>> building classes of scalar types and arrays. >> >> I don't know how one could implement "interfaces" without a tag. > > You have the tag in the representation of untagged'Class. You don't have > it > in the representation of untagged. Doesn't work, as I've previously explained. You have to be able to inherit implementation of operations, for all types. And there exist plenty of Ada types for which copying is not allowed. 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. You can of course adopt severely incompatible rules (can't inherit operations for derived limited types) or add complexity by making a new kind of derivation (you can't get rid of the old kind, so you're adding lots of new complexity without eliminating any old complexity). Neither sound appealing to me. For a new Ada-like language, the choices are different, but for Ada itself, it doesn't really work. I've explained this several times already and I'm not bothering to do so again. >>>>> We also nd "extension" that drops parent's representation altogether. >>>>> E.g. something like: >>>>> >>>>> type Character is new Unsigned_8 -- or enumeration, whatever >>>>> and Wide_Wide_Character'Interface; ... >> You miss my point: the effect is to make *every* operation in *every* >> subprogram -- including specific ones -- dispatching -- which would be >> way >> too expensive in practice (no optimization would be possible). > > Then it is wrong what you wrote. There will be no dispatch on specific > types. > > (I don't understand why you think that dispatching on specific types is > necessary) I've explained it previously and above again. You're welcome to disagree, but the only way to *prove* me wrong is to create a real proposal, in *Ada* terms, with proposed wording using *Ada* terminology, that does not have any significant incompatibilities. You've never made any attempt to address the real problems to this point, and I'm pretty certain that you can't. ... >> You are still misunderstanding. You'd *have* to have redispatch because >> the >> only way to implement inheritance would be to make all operations (even >> those very low-level ones) dispatching in *all* instances. There could be >> no >> statically bound operations. > > Yes, I still do not understand what has re-dispatch to do with inheritance > (of what?) > > The representation is NOT inherited > > Primitive operations (AKA, interface) are inherited in the way standard to > tagged types. That is, a NEW operation is declared with the same name and > the profile where the parent type is replaced by the descendant type. > > The way its body is generated out of old body with parent type converted > to > the descendant type in- and/or out. > > How this requires re-dispatch? The type conversions are view conversions, and they never make copies. 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), 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. ... > I don't ban inheritance of the representation. I want to be able not to do > it when I don't need it, e.g. for character and string types. But it's not that easy. If you have an array of tasks: type Foo (1 .. 10) of Some_Task with Component_Size => 32; and you derive another array of tasks from it: type New_Foo is new Foo with Component_Size => 64; This is legal, and you have different representations. >> It really kills the entire idea. > > No, IF String inherited the representation of Wide_Wide_String, THAT would > kill the idea. > > The whole idea is not to inherit irrelevant representations! I don't see the problem here; if Root_String is an abstract tagged type, the various concrete types derived from it all have completely diifferent representations. It's the same as happens for controlled types: there is no requirement that the representation of different controlled types is the same. This is standard stuff - if you don't want to inherit a representation, then don't, inherit from an abstract type (or interface, if you prefer) that has no representation. Don't try to get rid of an already existing representation, because that makes real trouble for inherited operations. ... > The bottom line is, I regard Ada 83 construct "type S is new T;" as very > useful, and wished it be valid with all specific types without silly > exceptions Ada 95 made for tagged types. Fair enough. I regard "type S is new T;" as a junk piece of syntax that was inherited from Ada 83, and should never be used. We completely disagree on this one, and there really is nothing worth talking about. You previously asked about: type Velocity is new Float; That would get you a repremand if you worked for me. You never, ever use the types in Standard (because they're not necessarily portable to other compilers). You derive types based on your actual application requirements: type Velocity is digits 5 range -1.0E+10 .. 1.0E+10; And let the compiler pick the representation. Similarly, if you are matching hardware, you declare types that match that hardware (specify Size, Object_Size, etc.). If you're writing true throw-away code, just use the types in Standard directly and forget the strong typing (it's throw-away, after all). There are so few cases that don't fit in one of these that it doesn't pay to have the feature in the language. Especially if we can fix the "renaming of the contents of an instantiation" problem somehow. ... >> The only way I know of to implement multiple inheritance is with >> a linked-list of tags, which isn't too bad when only a few interfaces are >> involved. But once you get the dozens you're talking about, it's going to >> cause a very significant overhead. > > There is no overhead on any existing Ada program. Only if the compiler-writer can implement many special cases in their code. I think this is unlikely; perhaps AdaCore has the resources to pull it off, but I doubt that any other vendor does. Janus/Ada tends to implement all types with the same code and optimize to better code, meaning the most general case is the typically the only thing that we implement. It wouldn't be possible to optimize that to anything remotely like the existing Ada code, certainly not with the resources we have. And we'd be going backwards at best - no thanks. ... >> Because you need operations that work on every object, >> copyable or not. Remember, there are no type conversions between types in >> different hierarchies. > > And, this is what different hierarchies are for. For what? To make it impossible to pass integers to Text_IO, or to use them to instantiation Text_IO? (If you can't convert, you can't instantiate or use 'Class either.) How is that going to help make Ada more regular?? ... > And cloning is there to enforce checking. Huh? You get checking every time you make a new type, whether it is in the same hierarchy or a different one. The hierarchy defines what conversions are allowed (to/from 'Class, between related types). That's it. The type checking for specific types is exactly the same either way. ... >>> But they are still the same >>> hierarchy. You need some fundamental operation which tells that a type >>> breaks off the hierarchy. >> >> Yes, of course all containers ought to be members of the same hierarchy. >> How >> else would you create generic algorithms? > > Easily. Cloning borrows all operations. Define algorithm on the original > type. Then clone it. Done! But you have cloned nothing. Either you have a conversion to the original type, in which case they belong to the same hierarchy. Or you don't have a conversion, and then you can't inherit any implementations, because that involves conversions. >>>> As soon as user-defined things are involved, preference rules simply >>>> don't work. >>> >>> Some rules are clearly needed to choose between: >>> >>> function "&" (Left : String; Right : Wide_String) return Wide_String; >>> function "&" (Left : String; Right : Wide_String) return String; >> >> There are no such operations predefined in Ada, and that's because you >> *can't* chose between them. You can of course declare them yourself >> (that's >> essentially what happens in Ada.Strings.Unbounded), but the net effect is >> that you then cannot use literals with such a type. Ada does not attempt >> to >> prevent you from shooting yourself in the head. :-) > > Are you seriously going to propose a string class without "&"? A string class with a mixed & is nonsense. (I think the String & Character in Ada 83 was nonsense, but it's not a problem here.) The only & is String & String = String, and so on for all types. For compatibility, we'd also have String & Element = String. Nothing else -- no mixed string types. You never need such types anyway, they just make understanding of an expression impossible. >>> My take on this that the language should prevent situations when you >>> have >>> an object with some of its operations invisible, especially, when these >>> operations override the same primitive operation. I think this should be >>> possible to do while keeping it backward compatible, because standard >>> types are always visible anyway. >> >> Huh? This is very common with private types. With interfaces, we enforced >> such a rule and it is rather limiting. >> >> Claw uses hidden operations on window objects to keep the mechanisms of >> the >> message loop hidden away. > > I didn't meant that. Whether public or private an operation on the object > should be visible if you would see it otherwise, e.g. through use-clause. I think that's already the case. The problem is with "additional operations" that appear when you know more about a type, and that's completely related to private types and nesting. In my Ada-like language, I would ban that from happening, but it's 30 years too late for Ada in this way. ... >> You can do this sort of thing in exceedingly simple cases. But it simply >> gets too complex the more properties that you try to decompose on. And >> every >> such property is making all of your dispatching calls slower and slower. > > I would gladly buy that in exchange for how it is now: 100+ generic > packages, 1000+ instances, 4 hours compilation time, no way to compile on > a > 32-bit host. Fair enough; the problem is that you're in a very small minority. I know I would not accept that kind of slow-down in my code, especially if there was no corresponding benefit for me. >> Moreover, most interesting properties are not binary like the file mode. >> They tend to depend on the *values* of parameters, and often on >> combinations >> of values. It just is too complex to do. > > It is becomes increasingly expensive not to do it. There is a language > damage as well inflicted by all hacks of Ada 2005-2012. Further hacks are > in the pipe line, I guess. No idea, we haven't done much yet, private musings by me means little. I think there would be an argument for the position that we're reaching the limit of what we can do sensibly to Ada, and that we might have to make a clean break at some point to get rid of all of the legacy garbage. But I suspect that there wouldn't be enough customers for that sort of incompatible change. (See all of the problems the Python people are having from when they did that.) >>> It is not about checking, especially because the above construct is >>> still >>> possible to get through generics. It is just a stupid limitation >>> motivated >>> by urban legends mindlessly repeated through (using you wording) >>> OO-baloney >>> texts. >> >> Implementability is hardly an "urban legend". If the resulting code is >> too >> slow to use > > I saw no significant overhead in C++ programs, which has full MI from the > start. C++ is free of some of the Ada 83 legacy that weighs us down. There's a reason that Ada never will allow redefining of ":=", for one example. (I'm also dubious of your actual assertion; you probably aren't looking in the right places. I certainly can believe that you aren't seeing that slow-down, perhaps other effects predominate. I know I would see it, but of course I can't say how significant it would be without actually benchmarking it -- which isn't going to happen because I'm surely not implementing you're imaginative language.) Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-02 0:40 ` Randy Brukardt @ 2013-04-02 8:44 ` Dmitry A. Kazakov 2013-04-02 21:54 ` Randy Brukardt 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-02 8:44 UTC (permalink / raw) On Mon, 1 Apr 2013 19:40:42 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:1gnmajx2fdjju.1bo28xwmzt1nr.dlg@40tude.net... > .... >> The point is that whether you create a totally new string hierarchy or >> create one for already existing string types, you will have the issue with >> "&" (and any other operation with more than one argument/result of string >> type). That is *independent* on whatever Ada did or not before. It is in >> the nature of a multi-method, which "&" is. If you want a hierarchy of >> strings you *must* face this problem. > > No you don't. There are no language-defined multi-methods. String & String = > String is not a multi-method. Once String becomes member of a class it is. For the operation "&" there exist only two possibilities, Either it is a primitive operation of the class and so a multi-method, or else it is declared individually on each member of the class in separate packages (somewhere after the freezing point). The later variant is so silly that I don't even consider it. > You, the user, can define such operations, of > course, but then you have the deal with the consequences. Generally, it's > best if you don't do that. What is the use of a string type without operations? >>>> The model of Ada 95 tagged types provides a class with shared >>>> representations. This need to be augmented for the case when >>>> representations has to be different. Note that this was partially done when >>>> Java interfaces were added in Ada 2005. Java interface is a type without >>>> any representation, so there is nothing to inherit from, except for a slot >>>> for the type tag. Drop that slot, and you will have a workable model for >>>> building classes of scalar types and arrays. >>> >>> I don't know how one could implement "interfaces" without a tag. >> >> You have the tag in the representation of untagged'Class. You don't have >> it in the representation of untagged. > > Doesn't work, as I've previously explained. You said that it would not fit into Ada 83 derived types model. I answered that it never considered within that model. The model to augment is Ada 95 tagged types. > You have to be able to inherit > implementation of operations, for all types. It is already not so. See Ada 95 abstract primitive operations and operations dispatching in the result. They are NOT inherited. The programmer is asked to override them, because the compiler has no idea how to implement them. > And there exist plenty of Ada > types for which copying is not allowed. No problem. See above. All primitive operation will be inherited abstract if the representation is not inherited and no [user-defined] conversion defined (e.g. for a by-reference type). > 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. > The type conversions are view conversions, and they never make copies. View conversions will be kept for tagged types and not introduced for untagged ones. > 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. > 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. >> I don't ban inheritance of the representation. I want to be able not to do >> it when I don't need it, e.g. for character and string types. > > But it's not that easy. If you have an array of tasks: > > type Foo (1 .. 10) of Some_Task with Component_Size => 32; > > and you derive another array of tasks from it: > > type New_Foo is new Foo with Component_Size => 64; > > This is legal, and you have different representations. Irrelevant. Ada 83 derivation (cloning) is orthogonal to Ada 95 extension model. We are talking about the later. >>> It really kills the entire idea. >> >> No, IF String inherited the representation of Wide_Wide_String, THAT would >> kill the idea. >> >> 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. >> The bottom line is, I regard Ada 83 construct "type S is new T;" as very >> useful, and wished it be valid with all specific types without silly >> exceptions Ada 95 made for tagged types. > > Fair enough. I regard "type S is new T;" as a junk piece of syntax that was > inherited from Ada 83, and should never be used. We completely disagree on > this one, and there really is nothing worth talking about. > > You previously asked about: > > type Velocity is new Float; > > That would get you a repremand if you worked for me. You never, ever use the > types in Standard (because they're not necessarily portable to other > compilers). You derive types based on your actual application requirements: > > type Velocity is digits 5 range -1.0E+10 .. 1.0E+10; This is a bad design pattern because it refers to some magic numbers spread all over the source code, a huge maintenance problem, potentially. The proper pattern would be: type Measurement is digits 5 range -1.0E+10 .. 1.0E+10; ... type Velocity is new Measurement; type Acceleration is new Measurement; ... >>> Because you need operations that work on every object, >>> copyable or not. Remember, there are no type conversions between types in >>> different hierarchies. >> >> And, this is what different hierarchies are for. > > For what? To make it impossible to pass integers to Text_IO, or to use them > to instantiation Text_IO? It is in the same generic formal class, thus instantiation is possible. You are confusing generic classes, and classes induced by cloning, and classes induced by interface inheritance. They are not same. There is an infinite number of means by which some types could be lumped into a class. Class is no more than a set of types. E.g. all types which declarations start at the source code line 123 is a class. That does not make them possible or not to be used in Text_IO instantiation. That would be some other class. >>>> But they are still the same >>>> hierarchy. You need some fundamental operation which tells that a type >>>> breaks off the hierarchy. >>> >>> Yes, of course all containers ought to be members of the same hierarchy. >>> How else would you create generic algorithms? >> >> Easily. Cloning borrows all operations. Define algorithm on the original >> type. Then clone it. Done! > > But you have cloned nothing. I did types, literals, operations. > Either you have a conversion to the original > type, in which case they belong to the same hierarchy. This is a possible way to implement cloning. This is not the semantics of. The semantics is that there is a new set of types, values and operations with the properties of the original. Nothing more. > A string class with a mixed & is nonsense. (I think the String & Character > in Ada 83 was nonsense, but it's not a problem here.) It would be interesting to learn how many c.l.a. readers share such an extreme view. To me "&" is one of the most important requirements on string class design. It is also a good test for the language type system maturity. > The only & is String & String = String, and so on for all types. Totally useless, IMO. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-02 8:44 ` Dmitry A. Kazakov @ 2013-04-02 21:54 ` Randy Brukardt 2013-04-03 8:54 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-04-02 21:54 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:3gv2jwc95otm.pl2aahsh9ox8.dlg@40tude.net... > On Mon, 1 Apr 2013 19:40:42 -0500, Randy Brukardt wrote: > >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >> news:1gnmajx2fdjju.1bo28xwmzt1nr.dlg@40tude.net... >> .... >>> The point is that whether you create a totally new string hierarchy or >>> create one for already existing string types, you will have the issue >>> with >>> "&" (and any other operation with more than one argument/result of >>> string >>> type). That is *independent* on whatever Ada did or not before. It is in >>> the nature of a multi-method, which "&" is. If you want a hierarchy of >>> strings you *must* face this problem. >> >> No you don't. There are no language-defined multi-methods. String & >> String = >> String is not a multi-method. > > Once String becomes member of a class it is. For the operation "&" there > exist only two possibilities, Either it is a primitive operation of the > class and so a multi-method, or else it is declared individually on each > member of the class in separate packages (somewhere after the freezing > point). The later variant is so silly that I don't even consider it. I agree that latter variant is silly, but the notion that somehow "&" becomes a multi-method simply because it exists makes no sense. "=" is not a multi-method in Ada today for tagged types; "&" would work the same way - it does not take items of different types unless you explicitly convert them. Maybe you have a different idea of a multimethod than I do?? >> You, the user, can define such operations, of >> course, but then you have the deal with the consequences. Generally, it's >> best if you don't do that. > > What is the use of a string type without operations? Huh? There are predefined single-type operations. If you want mixed type operations, you have to define them, but it's usually a bad idea to do so. You're almost always better off with 'Class operands if you need type mixing -- for type resolution reasons (not even mentioning runtime issues). ... > You said that it would not fit into Ada 83 derived types model. I answered > that it never considered within that model. The model to augment is Ada 95 > tagged types. Tagged types need no augmentation -- they only work because they are by-reference types. They can't work without that, and you (rightly) want to get rid of that. >> You have to be able to inherit >> implementation of operations, for all types. > > It is already not so. See Ada 95 abstract primitive operations and > operations dispatching in the result. They are NOT inherited. The > programmer is asked to override them, because the compiler has no idea how > to implement them. Abstract operations have no implementation to override. Constructor functions are a special case where you would never want to share the implementation anyway. The fact that other functions aren't extended is a mistake in Ada, it makes it impractical to have those in your interfaces. The Claw Builder has types with a lot of functions and abstract routines, and the net effect is that it takes a week or more to create a single extension of the type - just to type in all of the bodies required. And the result of that is that extensions simply don't get built because the burden is too high. >> And there exist plenty of Ada >> types for which copying is not allowed. > > No problem. See above. All primitive operation will be inherited abstract > if the representation is not inherited and no [user-defined] conversion > defined (e.g. for a by-reference type). That was a bad idea for Ada 95 (there are pretty severe visibility issues associated with it), and I don't think it can be extended. 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. (Imagine extending Ada.Containers.Vectors if every routine became abstract. You'd never bother, because the effort to even write something to compiler would be so extreme. It's the exact opposite of agile programming [the only sane way to program, IMHO]. >> 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). The only way for this to work is for the low-level operations of the type to be implemented with dispatching calls -- this is exactly how generic units work in Janus/Ada. This requires a descriptor of some sort with every object and has the effect of re-dispatching. You are suggesting making such operations illegal (no inheritance), which does eliminate that problem but would make the resulting language unusable -- certainly in an agile sense. (The average private type having more than 100 operations once inherited and low-level ones that you want to break out are included.) >> The type conversions are view conversions, and they never make copies. > > View conversions will be kept for tagged types and not introduced for > untagged ones. Untagged types already have view conversions (it's what you pass to "in out" parameters in calls). You're 20 years too late with that idea. >> 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. >> 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*??? :-) >>> I don't ban inheritance of the representation. I want to be able not to >>> do >>> it when I don't need it, e.g. for character and string types. >> >> But it's not that easy. If you have an array of tasks: >> >> type Foo (1 .. 10) of Some_Task with Component_Size => 32; >> >> and you derive another array of tasks from it: >> >> type New_Foo is new Foo with Component_Size => 64; >> >> This is legal, and you have different representations. > > Irrelevant. Ada 83 derivation (cloning) is orthogonal to Ada 95 extension > model. We are talking about the later. Actually, there is only one model of inheritance in Ada. We're not making another one! There are slight differences in how the inheritance happens, but it's minor. In any case, there is no reason to separate derived from anything else: "type cloning" and "extension without new components" are the same thing -- you get a new type that's related to the current one only via explicit conversion and class-wide operations. >>>> It really kills the entire idea. >>> >>> No, IF String inherited the representation of Wide_Wide_String, THAT >>> would >>> kill the idea. >>> >>> 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? I'm interested in what we can do with tagged types. Forget the silly interfaces, or call it an interface if that makes people feel better (that's what we did with iterators, but it doesn't actually buy you anything). It's an Ada 95 abstract type. ... >> That would get you a repremand if you worked for me. You never, ever use >> the >> types in Standard (because they're not necessarily portable to other >> compilers). You derive types based on your actual application >> requirements: >> >> type Velocity is digits 5 range -1.0E+10 .. 1.0E+10; > > This is a bad design pattern because it refers to some magic numbers > spread > all over the source code, a huge maintenance problem, potentially. People how spread "magic numbers" all over the source code are idiots. In a real program, these would be constants declared in an appropriate package. That's Ada 101. I'm not putting that sort of organization in little examples, I would hope that is a given around here. > The proper pattern would be: > > type Measurement is digits 5 range -1.0E+10 .. 1.0E+10; > ... > type Velocity is new Measurement; > type Acceleration is new Measurement; > ... This is a terrible design pattern because it puts unrelated types together (and, allows them to be converted to a common ancestor, which almost always is a bug - especially if we had Measurement'Class). If I find that in our code somewhere, I'm going to remove it and try to find the offending programmer for an educational moment. :-) >>>> Because you need operations that work on every object, >>>> copyable or not. Remember, there are no type conversions between types >>>> in >>>> different hierarchies. >>> >>> And, this is what different hierarchies are for. >> >> For what? To make it impossible to pass integers to Text_IO, or to use >> them >> to instantiation Text_IO? > > It is in the same generic formal class, thus instantiation is possible. The "generic formal class" = hierarchy in Ada; if you split the hierarchy, then it's no longer in the same formal class. (That's the *meaning* of "class" in Ada; if you wanted truly unrelated things to work, it would have to be a "category" instead -- but there are no shared operations for categories as that does not make sense. And "categories" are never inherited.) > You are confusing generic classes, and classes induced by cloning, and > classes induced by interface inheritance. They are not same. I'm not confusing anything -- they *are* the same thing in Ada. I suppose you could introduce a whole new boatload of complexity to the language definition to make them different, but how you can call that a simplification is beyond me. > There is an infinite number of means by which some types could be lumped > into a class. Class is no more than a set of types. E.g. all types which > declarations start at the source code line 123 is a class. That does not > make them possible or not to be used in Text_IO instantiation. That would > be some other class. No, that's a "category" (in Ada terminology). Limited types are a "category", because that's not an inherited property. "Class" is always inherited: all members of a hierarchy rooted at a class have the same properties. >>>>> But they are still the same >>>>> hierarchy. You need some fundamental operation which tells that a type >>>>> breaks off the hierarchy. >>>> >>>> Yes, of course all containers ought to be members of the same >>>> hierarchy. >>>> How else would you create generic algorithms? >>> >>> Easily. Cloning borrows all operations. Define algorithm on the original >>> type. Then clone it. Done! >> >> But you have cloned nothing. > > I did types, literals, operations. > >> Either you have a conversion to the original >> type, in which case they belong to the same hierarchy. > > This is a possible way to implement cloning. This is not the semantics of. > The semantics is that there is a new set of types, values and operations > with the properties of the original. Nothing more. If they allow conversion (including implicitly to the class-wide root of the class) and instantiation, they're members of the same hierarchy. So it's the same as any other kind of extension inheritance (essentially a null extension). If it *doesn't* allow conversion and instantiation, then it's pretty useless (and it's not the same as Ada is today, which you claim you want to support). You do know that there are special rules for null extension so that you don't have to override any functions returning the type? Unlike normal extension, you only have to override abstract operations (which there should be none). So there would be no semantic difference between writing (if you could): type T is new W; and (which you can write): type T is new W with null record; I'm not actually sure why the former is disallowed, I think it's an intent to highlight the difference between tagged and untagged types. (And I don't know why we would want to highlight that!) >> A string class with a mixed & is nonsense. (I think the String & >> Character >> in Ada 83 was nonsense, but it's not a problem here.) > > It would be interesting to learn how many c.l.a. readers share such an > extreme view. > > To me "&" is one of the most important requirements on string class > design. > It is also a good test for the language type system maturity. > >> The only & is String & String = String, and so on for all types. > > Totally useless, IMO. Fair enough, we can agree to disagree on all of this. That's how Ada works today, and I've hardly ever heard anyone claim that Ada array types are "totally useless". Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-02 21:54 ` Randy Brukardt @ 2013-04-03 8:54 ` Dmitry A. Kazakov 2013-04-04 0:04 ` Randy Brukardt 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-03 8:54 UTC (permalink / raw) On Tue, 2 Apr 2013 16:54:01 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:3gv2jwc95otm.pl2aahsh9ox8.dlg@40tude.net... >> On Mon, 1 Apr 2013 19:40:42 -0500, Randy Brukardt wrote: >> >>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >>> news:1gnmajx2fdjju.1bo28xwmzt1nr.dlg@40tude.net... >>> .... >>>> The point is that whether you create a totally new string hierarchy or >>>> create one for already existing string types, you will have the issue with >>>> "&" (and any other operation with more than one argument/result of string >>>> type). That is *independent* on whatever Ada did or not before. It is in >>>> the nature of a multi-method, which "&" is. If you want a hierarchy of >>>> strings you *must* face this problem. >>> >>> No you don't. There are no language-defined multi-methods. String & >>> String = String is not a multi-method. >> >> Once String becomes member of a class it is. For the operation "&" there >> exist only two possibilities, Either it is a primitive operation of the >> class and so a multi-method, or else it is declared individually on each >> member of the class in separate packages (somewhere after the freezing >> point). The later variant is so silly that I don't even consider it. > > I agree that latter variant is silly, but the notion that somehow "&" > becomes a multi-method simply because it exists makes no sense. "=" is not a > multi-method in Ada today for tagged types; Assignment should certainly be a multi-method, because in some cases you want to be able to assign one type of the hierarchy to another. Assignment is a bit special case because the target's tag cannot be changed anyway. That reduces the number of use-cases for mixed types. Others could be further reduced using constrained subtypes, but they still exist. As a multi-method use case consider a tagged class with the operations "=" and "<" defined. These must support mixed types almost always. > "&" would work the same way - it > does not take items of different types unless you explicitly convert them. > Maybe you have a different idea of a multimethod than I do?? 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. >>> You, the user, can define such operations, of >>> course, but then you have the deal with the consequences. Generally, it's >>> best if you don't do that. >> >> What is the use of a string type without operations? > > Huh? There are predefined single-type operations. If you want mixed type > operations, you have to define them, It would be a combinatorial explosion of variants and a huge issue with visibility. The language should support this use case, because it is a pattern for all dyadic operations, assignment, comparisons. > but it's usually a bad idea to do so. > You're almost always better off with 'Class operands if you need type > mixing -- for type resolution reasons (not even mentioning runtime issues). That does not solve the problem, you will get Constraint_Error. The only pattern that sometimes works is recursive cascaded dispatch. That is when you make one argument controlled and another class-wide. 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. >>> And there exist plenty of Ada >>> types for which copying is not allowed. >> >> No problem. See above. All primitive operation will be inherited abstract >> if the representation is not inherited and no [user-defined] conversion >> defined (e.g. for a by-reference type). > > That was a bad idea for Ada 95 (there are pretty severe visibility issues > associated with it), and I don't think it can be extended. It was a great Ada 95 idea, because covariant out-operations are unsafe to inherit under type extension. *The compiler shall not make any assumptions* > 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. 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. >>> 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. >>> 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. >>> 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. >>>>> It really kills the entire idea. >>>> >>>> No, IF String inherited the representation of Wide_Wide_String, THAT >>>> would kill the idea. >>>> >>>> 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'm interested in what we can do with tagged types. Forget the silly > interfaces, or call it an interface if that makes people feel better (that's > what we did with iterators, but it doesn't actually buy you anything). It's > an Ada 95 abstract type. If so, allow to inherit from more than one. Allow to inherit only interface from such a type. You have the problem of "&" at hand. It cannot be solved without the above mechanisms. And multi-method and MI is only a start. The real problem is *full* MD as "&" is defined on String and Character. >> The proper pattern would be: >> >> type Measurement is digits 5 range -1.0E+10 .. 1.0E+10; >> ... >> type Velocity is new Measurement; >> type Acceleration is new Measurement; >> ... > > This is a terrible design pattern because it puts unrelated types together > (and, allows them to be converted to a common ancestor, which almost always > is a bug - especially if we had Measurement'Class). They are related, Acceleration is computed from Velocity and Duration. On top of that come a huge pile of generics (can't rid of them) instantiated with Measurement, e.g. I/O, GUI stuff. In real-life case you can't do that with individual types. You need a class and this is what Measurement is for. >>> Either you have a conversion to the original >>> type, in which case they belong to the same hierarchy. >> >> This is a possible way to implement cloning. This is not the semantics of. >> The semantics is that there is a new set of types, values and operations >> with the properties of the original. Nothing more. > > If they allow conversion (including implicitly to the class-wide root of the > class) and instantiation, they're members of the same hierarchy. The semantics for tagged types (if they were supported) should be creating a new type for each parent type. type T is new Ada,Finalization.Controlled with ...; type Q is new T; X : Q; Y : Ada.Finalization.Controlled'Class := X; -- Type error Z : Ada.Finalization.Controlled'Class := T (X); -- OK Q is not an extension of Ada,Finalization.Controlled. It is of some anonymous type cloned from Ada,Finalization.Controlled: type <anonymous> is new Ada,Finalization.Controlled; -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-03 8:54 ` Dmitry A. Kazakov @ 2013-04-04 0:04 ` Randy Brukardt 2013-04-04 8:26 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-04-04 0:04 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:1gkxiwepaxvtt$.u3ly33rbwthf.dlg@40tude.net... > On Tue, 2 Apr 2013 16:54:01 -0500, Randy Brukardt wrote: > >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >> news:3gv2jwc95otm.pl2aahsh9ox8.dlg@40tude.net... >>> On Mon, 1 Apr 2013 19:40:42 -0500, Randy Brukardt wrote: >>> >>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >>>> news:1gnmajx2fdjju.1bo28xwmzt1nr.dlg@40tude.net... >>>> .... >>>>> The point is that whether you create a totally new string hierarchy or >>>>> create one for already existing string types, you will have the issue >>>>> with >>>>> "&" (and any other operation with more than one argument/result of >>>>> string >>>>> type). That is *independent* on whatever Ada did or not before. It is >>>>> in >>>>> the nature of a multi-method, which "&" is. If you want a hierarchy of >>>>> strings you *must* face this problem. >>>> >>>> No you don't. There are no language-defined multi-methods. String & >>>> String = String is not a multi-method. >>> >>> Once String becomes member of a class it is. For the operation "&" there >>> exist only two possibilities, Either it is a primitive operation of the >>> class and so a multi-method, or else it is declared individually on each >>> member of the class in separate packages (somewhere after the freezing >>> point). The later variant is so silly that I don't even consider it. >> >> I agree that latter variant is silly, but the notion that somehow "&" >> becomes a multi-method simply because it exists makes no sense. "=" is >> not a >> multi-method in Ada today for tagged types; > > Assignment should certainly be a multi-method, because in some cases you > want to be able to assign one type of the hierarchy to another. Assignment > is a bit special case because the target's tag cannot be changed anyway. > That reduces the number of use-cases for mixed types. Others could be > further reduced using constrained subtypes, but they still exist. > > As a multi-method use case consider a tagged class with the operations "=" > and "<" defined. These must support mixed types almost always. > >> "&" would work the same way - it >> does not take items of different types unless you explicitly convert >> them. >> Maybe you have a different idea of a multimethod than I do?? > > 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). So here again we must agree to disagree. >>>> You, the user, can define such operations, of >>>> course, but then you have the deal with the consequences. Generally, >>>> it's >>>> best if you don't do that. >>> >>> What is the use of a string type without operations? >> >> Huh? There are predefined single-type operations. If you want mixed type >> operations, you have to define them, > > It would be a combinatorial explosion of variants and a huge issue with > visibility. The language should support this use case, because it is a > pattern for all dyadic operations, assignment, comparisons. 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. >> but it's usually a bad idea to do so. >> You're almost always better off with 'Class operands if you need type >> mixing -- for type resolution reasons (not even mentioning runtime >> issues). > > That does not solve the problem, you will get Constraint_Error. You don't get Constraint_Error when one of the arguments is class-wide: function Is_Same (Left : A_Type; Right : Root_Type'Class) return Boolean; There is no automatic reason for this to raise Constraint_Error. You do have to implement this, of course, and whether that can easily be done depends on the operations of your class-wide type -- but that's all under the control of the programmer. > 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. > 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. 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. 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. It would require there to be critical bugs in Ada (or critical needs) for the (current) ARG to take on such changes. You aren't even willing to write up real use-cases where the existing language has problems (because I've asked that you do that in the past) -- without those there is no chance that any significant changes will be entertained here. ... >> 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. > 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 suspect that this would just be too complex for the average Ada user to understand. It took me a long time to understand inheritance at all -- I never did understand it in Ada 83 and it took a huge amount of effort (and creating several large libraries using it) before I got any feeling for it at all. >>>> 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. You'd have to forcibly specify one or the other for all types, which is certain to be incompatible with existing implementations. 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). That would mean that the behavior of such a conversion would be very different for an untagged type and for a tagged type. Not sure if that is a real problem, but it certainly would be the sort of thing we would not want to be true. (Essentially this would mean that re-dispatching is not possible for untagged objects. I agree that re-dispatching is usually a mistake, but sometimes you need it -- we did use it in Claw in a few instances for message delivery, for example.) >>>> 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). It also could cause problems if such a call occurred inside of an Adjust or Finalize, you could unintentionally cause an infinite regress. >>>> 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? It's like the 1986 tax simplification in the US; they eventually renamed it to "tax reform" because in the end nothing was simplified. >>>>>> It really kills the entire idea. >>>>> >>>>> No, IF String inherited the representation of Wide_Wide_String, THAT >>>>> would kill the idea. >>>>> >>>>> 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. >> I'm interested in what we can do with tagged types. Forget the silly >> interfaces, or call it an interface if that makes people feel better >> (that's >> what we did with iterators, but it doesn't actually buy you anything). >> It's >> an Ada 95 abstract type. > > If so, allow to inherit from more than one. Allow to inherit only > interface > from such a type. That's why we'd probably define it as an interface, so that misguided people like you will feel better. :-) I find no value whatsoever to interfaces without a skelton shared implementation, so I want components and concrete operations in any type. And implementing full MI is prohibitively expensive, on top of which it's usually not the best solution anyway. > You have the problem of "&" at hand. It cannot be solved > without the above mechanisms. And multi-method and MI is only a start. The > real problem is *full* MD as "&" is defined on String and Character. We can agree to disagree on the above. You are just babbling in my view -- I see no problem at all with "&". Combining different types in an ad-hoc way is the same as not having typing at all in terms of error detection. You need more than just a definition of what happens when type A is converted to type B, you also have to require almost all conversions to be explicit. And once you do that, multi-methods are virtually never needed. ... >>> The proper pattern would be: >>> >>> type Measurement is digits 5 range -1.0E+10 .. 1.0E+10; >>> ... >>> type Velocity is new Measurement; >>> type Acceleration is new Measurement; >>> ... >> >> This is a terrible design pattern because it puts unrelated types >> together >> (and, allows them to be converted to a common ancestor, which almost >> always >> is a bug - especially if we had Measurement'Class). > > They are related, Acceleration is computed from Velocity and Duration. On > top of that come a huge pile of generics (can't rid of them) instantiated > with Measurement, e.g. I/O, GUI stuff. In real-life case you can't do that > with individual types. You need a class and this is what Measurement is > for. Your real-life is obviously completely different than mine. There are almost no generics in any of our code (especially in the compiler). And even if there were, I'd be happy to have as many instantiations as needed -- code shared generic instances are pretty cheap to create. ... >>>> Either you have a conversion to the original >>>> type, in which case they belong to the same hierarchy. >>> >>> This is a possible way to implement cloning. This is not the semantics >>> of. >>> The semantics is that there is a new set of types, values and operations >>> with the properties of the original. Nothing more. >> >> If they allow conversion (including implicitly to the class-wide root of >> the >> class) and instantiation, they're members of the same hierarchy. > > The semantics for tagged types (if they were supported) should be creating > a new type for each parent type. > > type T is new Ada,Finalization.Controlled with ...; > type Q is new T; > > X : Q; > Y : Ada.Finalization.Controlled'Class := X; -- Type error > Z : Ada.Finalization.Controlled'Class := T (X); -- OK > > Q is not an extension of Ada,Finalization.Controlled. It is of some > anonymous type cloned from Ada,Finalization.Controlled: > > type <anonymous> is new Ada,Finalization.Controlled; Sure, but what does this mean? If there is no conversion or instantiation associated with this new type, it's useless. (You'd need to duplicate all of the code associated with it.) And if there is, it's not a separate hierarchy. Anyway, this is getting pointless (especially this last part). I think this discussion is pretty much done, so I'm going to try to refrain from answering any more on this. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-04 0:04 ` Randy Brukardt @ 2013-04-04 8:26 ` Dmitry A. Kazakov 2013-04-04 20:31 ` Randy Brukardt 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-04 8:26 UTC (permalink / raw) On Wed, 3 Apr 2013 19:04:24 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> 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 ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-04 8:26 ` Dmitry A. Kazakov @ 2013-04-04 20:31 ` Randy Brukardt 2013-04-05 9:57 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-04-04 20:31 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:1fmcdkj58brky.bjedt0pr39cd$.dlg@40tude.net... > On Wed, 3 Apr 2013 19:04:24 -0500, Randy Brukardt wrote: > >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> 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? The same way it is an error to compare a float and an integer. You could make a rule with somewhat sensible results, but it's a bad idea because it hides more errors than it simplifies correct code. >> 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); This is clearly class-wide: procedure Set_Text (Control : Edit_Box; Text : Root_String_Type'Class); The implementation would use the constructor for Text to create the value, so it's straightforward to implement. (The Edit_Box has to have some particular representation for text, even if the result does not.) >>> 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. Which is 95% of the cases that you would want. >>> 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. Mixed operations are almost always a non-starter for any type. >> 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. I have no idea how that could work. Resolution is a very complex business both to define and to implement. It's hopeless for ordinary users to be able to make sense of it, and the implementation seems like it would be impossible. Moreover, unbounded preference rules also means unbounded maintenance headaches (preference rules almost always causing bad behavior). Generally, it's the lack of overloading, not the provision for more, that causes the trouble. ... >> 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. You can, but it's virtually worthless to do so. It's simply too much work for any supposed benefit. (Not that I expect you to believe this.) >>> 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. You have to avoid this sort of thing, the Ada 95 effects make it absolutely necessary to avoid functions returning a controlled type, else creating extensions is so hard that no one will do it. And to avoid them you have to understand it. ... >>>>>> 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.] It doesn't work for portability reasons for some compilers to call Adjust during the evaluation of parameters and other compilers to not call Adjust. It would make performance wildly variable and possibly cause bugs (if the program unintentionally depended on one or the other. >> 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. Thus making most Ada code non-portable. That's a great idea. :-( >> 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. Objects of limited types are always assumed to have an identity; that's why they can't be copied. ... >>> 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. Because currently, you don't call Adjust/Finalize for a type conversion. And it would have to be specified whether a type is by-copy or by-reference (it could not be left to the compiler with these rules, as I previously mentioned) -- that means compilers would have to change in some cases. ... >> 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. That's already true, you just don't have inheritance of operations for these hierarchies. So exactly what you are simplifying but introducing this whole new notion of type cloning, this new notion of when you must override routines, and so on?? >>>>>>> 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. Yes, or from related ones. There is no significant value to doing anything else - as you point out, if you can inherit the operations, the representations have to be compatible. So there is nothing useful you can do with multiple levels. And if you want pure inheritance of (non-string) interfaces, then mix in some interfaces with your types (forget normal derivation in that case). Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-04 20:31 ` Randy Brukardt @ 2013-04-05 9:57 ` Dmitry A. Kazakov 2013-04-05 12:45 ` Stefan.Lucks 2013-04-06 1:20 ` Randy Brukardt 0 siblings, 2 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-05 9:57 UTC (permalink / raw) On Thu, 4 Apr 2013 15:31:23 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:1fmcdkj58brky.bjedt0pr39cd$.dlg@40tude.net... >> On Wed, 3 Apr 2013 19:04:24 -0500, Randy Brukardt wrote: >> >>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> 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? > > The same way it is an error to compare a float and an integer. It is not same. R and Z are different mathematical constructs. Unicode strings, all of them, are semantically exactly same except for encoding [representation] and constraints put on the code point set. > You could > make a rule with somewhat sensible results, but it's a bad idea because it > hides more errors than it simplifies correct code. If that were so, you should not have them in the same hierarchy. You want to have one class in order to share operations like Put_Line. These operations are far more questionable than comparison. If you challenge comparison, you should not do Put_Line either. You design decisions are motivated by compiler implementation issues not by the actual properties of strings. >>> 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); > > This is clearly class-wide: > > procedure Set_Text (Control : Edit_Box; Text : Root_String_Type'Class); > > The implementation would use the constructor for Text to create the value, > so it's straightforward to implement. (The Edit_Box has to have some > particular representation for text, even if the result does not.) Now this: function Get_Text (Control : Edit_Box) return 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. > > Which is 95% of the cases that you would want. No more than 20-30% actually. >>>> 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. > > Mixed operations are almost always a non-starter for any type. Mixed operations are a must for all algebraic types and all string types. Ada 83 had it mixed from the start, e.g. Universal_Integer vs. Integer. Ada 95 added mixed operations for access types. Without mixed operations, hierarchies of scalar type, strings, access types were useless. >> 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. > > You have to avoid this sort of thing, You cannot avoid it, because there is no way the compiler could define it semantically correct. > the Ada 95 effects make it absolutely > necessary to avoid functions returning a controlled type, else creating > extensions is so hard that no one will do it. I don't know where you get that idea. I never had any problem with abstract factories. Actual problem is fighting senseless limitations imposed by the language, which makes design very hard as you never know if the derived type would be possible to construct. Limited aggregates/functions, broken initialization/finalization, leaking separation of specification and implementation, missing initialization/finalization of class-wides etc. That makes it difficult. >> 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.] > > It doesn't work for portability reasons for some compilers to call Adjust > during the evaluation of parameters and other compilers to not call Adjust. When the type neither specified as either by-reference nor as by-value, it shall be exactly this way. I don't understand why this is relevant. > It would make performance wildly variable and possibly cause bugs (if the > program unintentionally depended on one or the other. Yes, the language permits compilers implemented poorly, and? >>> 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. > > Thus making most Ada code non-portable. No more than they already are. The program that exploits certain type of parameter passing for a type which is not specified as either by value or by reference is erroneous. End of story. >>> 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. > > Objects of limited types are always assumed to have an identity; No. E.g. task and protected types lack type identity. Only tagged types have type identity. Note that type identity /= object identity (e.g. machine address where the object resides). >>>> 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. > > Because currently, you don't call Adjust/Finalize for a type conversion. And > it would have to be specified whether a type is by-copy or by-reference (it > could not be left to the compiler with these rules, as I previously > mentioned) -- that means compilers would have to change in some cases. No, it will stay exactly as it is now. Type conversion is irrelevant. >>> 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. > > That's already true, you just don't have inheritance of operations for these > hierarchies. So exactly what you are simplifying but introducing this whole > new notion of type cloning, this new notion of when you must override > routines, and so on?? I don't introduce anything Ada 83 or 95 do not have already. I want to lift meaningless language limitations which lead to silly design decisions like inability to concatenate or compare two strings. >> You want to derive each string type straight from Root_String. > > Yes, or from related ones. There is no significant value to doing anything > else - as you point out, if you can inherit the operations, the > representations have to be compatible. So there is nothing useful you can do > with multiple levels. Encoding! -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-05 9:57 ` Dmitry A. Kazakov @ 2013-04-05 12:45 ` Stefan.Lucks 2013-04-05 12:49 ` Stefan.Lucks 2013-04-05 14:36 ` Dmitry A. Kazakov 2013-04-06 1:20 ` Randy Brukardt 1 sibling, 2 replies; 242+ messages in thread From: Stefan.Lucks @ 2013-04-05 12:45 UTC (permalink / raw) [-- Attachment #1: Type: TEXT/PLAIN, Size: 2585 bytes --] On Fri, 5 Apr 2013, Dmitry A. Kazakov wrote: >>> How is it an error to compare String and Wide_String? >> >> The same way it is an error to compare a float and an integer. > > It is not same. R and Z are different mathematical constructs. Sure! This is different from string types, where the distinction between String, Wide_String, Wide_Wide_String, and whatever comes next has historical reasons. It makes mixing narrow, Wide_ and Wide_Wide_ Strings worse than mixing reals and integers. > Unicode strings, all of them, are semantically exactly same except for > encoding [representation] and constraints put on the code point set. N is a subset of Z is a subset of Q is a subset of R. Furthermore, each "X is a subset of Y" relationship implies that any operation possible in X is also possible in Y, including comparisons. How are generalised strings simpler than generalised numbers? > Mixed operations are a must for all algebraic types and all string types. Well, Ada does make a clear distinction between Universal_Integer and Universal_Real. So why should it work for String types? > Ada 83 had it mixed from the start, e.g. Universal_Integer vs. Integer. Ada (all Adas from 83 to 2012) had two *different* algebraic root types. In any cases, there are good reasons why a program has sometimes to mix real and natural numbers. But what reasons would you have to actually mix narrow, Wide_ and Wide_Wide_ Strings? That is bad program design, anyway! It is error-prone low-level programming, quite similar to the C-style of using memory addresses and pointer arithmetic. If you *have* to do it, perhaps because you have to support some legacy interfaces, with different string types, you better hide the input/output stuff in some low-level packages, and use a single kind of string in your application logic (perhaps Wide_Wide_String, if the memory isn't too small). Of course, a single common root type for String, Bounded_String and Unbounded_String would come handy -- similarly another root type for the Wide_ and yet another for the Wide_Wide_ family. But note that not even Universal_Integer does provide such a root type! The Standard(-Library) did not even define any Bounded_Integer or Unbounded_Integer types to deal with huge integers, in contrast to strings. ------ I love the taste of Cryptanalysis in the morning! ------ <http://www.uni-weimar.de/cms/medien/mediensicherheit/home.html> --Stefan.Lucks (at) uni-weimar.de, Bauhaus-Universität Weimar, Germany-- ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-05 12:45 ` Stefan.Lucks @ 2013-04-05 12:49 ` Stefan.Lucks 2013-04-05 14:19 ` Dmitry A. Kazakov 2013-04-05 14:36 ` Dmitry A. Kazakov 1 sibling, 1 reply; 242+ messages in thread From: Stefan.Lucks @ 2013-04-05 12:49 UTC (permalink / raw) [-- Attachment #1: Type: TEXT/PLAIN, Size: 857 bytes --] On Fri, 5 Apr 2013, Stefan.Lucks@uni-weimar.de wrote: > On Fri, 5 Apr 2013, Dmitry A. Kazakov wrote: > >> Unicode strings, all of them, are semantically exactly same except for >> encoding [representation] and constraints put on the code point set. > > N is a subset of Z is a subset of Q is a subset of R. > > Furthermore, each "X is a subset of Y" relationship implies that any > operation possible in X is also possible in Y, including comparisons. What I meant to write: Numbers, naturals, integers, rationals and reals, are semantically exactly same except for encoding [representation] and constraints. ------ I love the taste of Cryptanalysis in the morning! ------ <http://www.uni-weimar.de/cms/medien/mediensicherheit/home.html> --Stefan.Lucks (at) uni-weimar.de, Bauhaus-Universität Weimar, Germany-- ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-05 12:49 ` Stefan.Lucks @ 2013-04-05 14:19 ` Dmitry A. Kazakov 2013-04-05 14:44 ` Stefan.Lucks 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-05 14:19 UTC (permalink / raw) On Fri, 5 Apr 2013 14:49:41 +0200, Stefan.Lucks@uni-weimar.de wrote: > On Fri, 5 Apr 2013, Stefan.Lucks@uni-weimar.de wrote: > >> On Fri, 5 Apr 2013, Dmitry A. Kazakov wrote: >> >>> Unicode strings, all of them, are semantically exactly same except for >>> encoding [representation] and constraints put on the code point set. >> >> N is a subset of Z is a subset of Q is a subset of R. Depends on construction. The proper statement is that Q has a subset equivalent to Z and R has a subset equivalent to Q. >> Furthermore, each "X is a subset of Y" relationship implies that any >> operation possible in X is also possible in Y, including comparisons. > > What I meant to write: > > Numbers, naturals, integers, rationals and reals, are semantically exactly > same except for encoding [representation] and constraints. A quite common misunderstanding. Structure such as field is not same as a subset. To see the difference between R and Z consider the following predicate: forall x in S exists y such as x=1/y [multiplicative inverse] This is true for S=R and false for S=Z. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-05 14:19 ` Dmitry A. Kazakov @ 2013-04-05 14:44 ` Stefan.Lucks 2013-04-05 16:11 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Stefan.Lucks @ 2013-04-05 14:44 UTC (permalink / raw) [-- Attachment #1: Type: TEXT/PLAIN, Size: 1252 bytes --] On Fri, 5 Apr 2013, Dmitry A. Kazakov wrote: >> Numbers, naturals, integers, rationals and reals, are semantically exactly >> same except for encoding [representation] and constraints. > > A quite common misunderstanding. Structure such as field is not same as a > subset. To see the difference between R and Z consider the following > predicate: > > forall x in S exists y such as x=1/y [multiplicative inverse] > > This is true for S=R and false for S=Z. Fair enough! But the same is true for N and Z: every in Z has an additive inverse, but not every number in N. If the non-existence of a multiplicative inverse would justify different root types for Z and R, why should the non-existence of an additive inverse not justify different root types for N and Z (Universal_Positive versus Universal_Integer). As it turns out, the fact that Naturals and Positives have the same representation as Integers, while Float has a different one, matters more than any "mathematical structure" ... ------ I love the taste of Cryptanalysis in the morning! ------ <http://www.uni-weimar.de/cms/medien/mediensicherheit/home.html> --Stefan.Lucks (at) uni-weimar.de, Bauhaus-Universität Weimar, Germany-- ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-05 14:44 ` Stefan.Lucks @ 2013-04-05 16:11 ` Dmitry A. Kazakov 2013-04-05 19:02 ` Stefan.Lucks 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-05 16:11 UTC (permalink / raw) On Fri, 5 Apr 2013 16:44:53 +0200, Stefan.Lucks@uni-weimar.de wrote: > On Fri, 5 Apr 2013, Dmitry A. Kazakov wrote: > >>> Numbers, naturals, integers, rationals and reals, are semantically exactly >>> same except for encoding [representation] and constraints. >> >> A quite common misunderstanding. Structure such as field is not same as a >> subset. To see the difference between R and Z consider the following >> predicate: >> >> forall x in S exists y such as x=1/y [multiplicative inverse] >> >> This is true for S=R and false for S=Z. > > Fair enough! > > But the same is true for N and Z: every in Z has an additive inverse, but > not every number in N. If the non-existence of a multiplicative inverse > would justify different root types for Z and R, why should the > non-existence of an additive inverse not justify different root types for > N and Z (Universal_Positive versus Universal_Integer). That depends solely on the application domain. When numbers are used as indices (ordinals) they require certain properties, e.g. to form an additive group. Other application domains require other properties. That is why the language shall not dictate which interfaces (and thus properties) a given type has to implement. > As it turns out, the fact that Naturals and Positives have the same > representation as Integers, while Float has a different one, matters more > than any "mathematical structure" ... Nope, representation never matter. Employee ID and task ID may have same representation. That does not mean anything. Nominal type equivalence was a corner stone of Ada design. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-05 16:11 ` Dmitry A. Kazakov @ 2013-04-05 19:02 ` Stefan.Lucks 2013-04-05 19:34 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Stefan.Lucks @ 2013-04-05 19:02 UTC (permalink / raw) [-- Attachment #1: Type: TEXT/PLAIN, Size: 2239 bytes --] On Fri, 5 Apr 2013, Dmitry A. Kazakov wrote: > On Fri, 5 Apr 2013 16:44:53 +0200, Stefan.Lucks@uni-weimar.de wrote: >> But the same is true for N and Z: every in Z has an additive inverse, but >> not every number in N. If the non-existence of a multiplicative inverse >> would justify different root types for Z and R, why should the >> non-existence of an additive inverse not justify different root types for >> N and Z (Universal_Positive versus Universal_Integer). > > That depends solely on the application domain. Ada is a general-purpose language. We are discussing Ada's type concept and not any specific application, so there is not "the application domain" anything could possibly depend on. >> As it turns out, the fact that Naturals and Positives have the same >> representation as Integers, while Float has a different one, matters more >> than any "mathematical structure" ... > > Nope, representation never matter. Employee ID and task ID may have same > representation. That does not mean anything. Nominal type equivalence was a > corner stone of Ada design. Dmitry, I admire your ability to make some correct claim, being out of topic, and then pretending that this claim makes your point! ;-) Sure, one of the main strengths of Ada from its beginning is allowing the programmer to define different and intentionally incompatible types with identical representations. But you are actually proposing the opposite: Making different types with different representations intentionally compatible by introducing some universal super-type and then formally deriving the different types from the super-type. Actually another corner stone of Ada has been the language designers' reluctance to introduce implicit conversions between types with different representations. Sure, some cases where implicit conversions take place exist, but only very few. One example is the conversion of constants of type Universal_Something into the right type. ------ I love the taste of Cryptanalysis in the morning! ------ <http://www.uni-weimar.de/cms/medien/mediensicherheit/home.html> --Stefan.Lucks (at) uni-weimar.de, Bauhaus-Universität Weimar, Germany-- ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-05 19:02 ` Stefan.Lucks @ 2013-04-05 19:34 ` Dmitry A. Kazakov 2013-04-05 20:23 ` Stefan.Lucks 2013-04-05 20:38 ` Stefan.Lucks 0 siblings, 2 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-05 19:34 UTC (permalink / raw) On Fri, 5 Apr 2013 21:02:43 +0200, Stefan.Lucks@uni-weimar.de wrote: > On Fri, 5 Apr 2013, Dmitry A. Kazakov wrote: > >> On Fri, 5 Apr 2013 16:44:53 +0200, Stefan.Lucks@uni-weimar.de wrote: > >>> But the same is true for N and Z: every in Z has an additive inverse, but >>> not every number in N. If the non-existence of a multiplicative inverse >>> would justify different root types for Z and R, why should the >>> non-existence of an additive inverse not justify different root types for >>> N and Z (Universal_Positive versus Universal_Integer). >> >> That depends solely on the application domain. > > Ada is a general-purpose language. Yes <=> Ada can be used for most application domains. > We are discussing Ada's type concept > and not any specific application, so there is not "the application domain" > anything could possibly depend on. We are discussing deficiencies of Ada type system, unable to capture relations between domain specific entities modeled as objects and types. E.g. few built-in numeric types, which are supposed to fit everything and expectedly fail, because predefined numbers have properties you might not need and miss ones you do need. The Op's subtype Prim was a perfect example of such a failure. Prime numbers are neither additive nor multiplicative. It is not a group. Yet Prime inherited the interface of a group from base type (Positive) and there is no way to prohibit this. It also inherited the order of Positives ('Succ), which is not one of Prime, and, again, there is no language means for fix that. > Sure, one of the main strengths of Ada from its beginning is allowing the > programmer to define different and intentionally incompatible types with > identical representations. How is representation relevant here? Two incompatible types are incompatible per programmer's wish, whichever representation they might have. Representation is an implementation detail. > But you are actually proposing the opposite: Making different types with > different representations intentionally compatible by introducing some > universal super-type and then formally deriving the different types from > the super-type. No, I insist that it is up to the programmer to decide whether two types to become compatible (relative) or not. Character and Wide_Character are evidently relative. Velocity and Acceleration are not (considering assignment operation and additive group operations). They are relative considering multiplication. This is why multiple inheritance is a key issue. > Actually another corner stone of Ada has been the language designers' > reluctance to introduce implicit conversions between types with different > representations. I disagree. They wanted to prevent the mess of PL/1 where *arbitrary* conversions were applied to semantically unrelated types. Types like Character and Wide_Character are semantically related. Conversion from one to another is perfectly well defined. > Sure, some cases where implicit conversions take place > exist, but only very few. One example is the conversion of constants of > type Universal_Something into the right type. It makes sense in all cases where types are related. This is simply the definition of a type S being a subtype of T <=> S is substitutable for T. If representations are different the substitution is done per conversion. Not a rocket science, really. And it is all up to the programmer to tell the compiler that S must be considered a subtype of T, whatever representation both might have is not language's business. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-05 19:34 ` Dmitry A. Kazakov @ 2013-04-05 20:23 ` Stefan.Lucks 2013-04-06 7:39 ` Dmitry A. Kazakov 2013-04-05 20:38 ` Stefan.Lucks 1 sibling, 1 reply; 242+ messages in thread From: Stefan.Lucks @ 2013-04-05 20:23 UTC (permalink / raw) [-- Attachment #1: Type: TEXT/PLAIN, Size: 2238 bytes --] On Fri, 5 Apr 2013, Dmitry A. Kazakov wrote: > On Fri, 5 Apr 2013 21:02:43 +0200, Stefan.Lucks@uni-weimar.de wrote: > No, I insist that it is up to the programmer to decide whether two types to > become compatible (relative) or not. Character and Wide_Character are > evidently relative. Integer and Float are "evidently relative". > I disagree. They wanted to prevent the mess of PL/1 where *arbitrary* > conversions were applied to semantically unrelated types. Types like > Character and Wide_Character are semantically related. Conversion from one > to another is perfectly well defined. The same for conversions between Integer and Float. >> Sure, some cases where implicit conversions take place >> exist, but only very few. One example is the conversion of constants of >> type Universal_Something into the right type. > > It makes sense in all cases where types are related. This is simply the > definition of a type S being a subtype of T <=> S is substitutable for T. And Integer is substitutable for Real. > If representations are different the substitution is done per conversion. > Not a rocket science, really. Clearly, the designers of Ada where reluctant to define an implicit conversion from Integer to Float. I am glad about that -- it frequently helps me catching errors. Similarly for the distinction between different String types. Sure, explicit conversions, are sometimes annoying, and so is the mess with constants. That is the same for string types as for arithmetic ones. E.g. I frequently get caught by the compiler writing, say, "2" where I would have to write "2.0" for a constant Float. > And it is all up to the programmer to tell the compiler that S must be > considered a subtype of T, whatever representation both might have is not > language's business. Arithmetic types and String types are in the same boat here. There is no logical reason to allow implicit conversions for one class and not for the other one. ------ I love the taste of Cryptanalysis in the morning! ------ <http://www.uni-weimar.de/cms/medien/mediensicherheit/home.html> --Stefan.Lucks (at) uni-weimar.de, Bauhaus-Universität Weimar, Germany-- ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-05 20:23 ` Stefan.Lucks @ 2013-04-06 7:39 ` Dmitry A. Kazakov 2013-04-07 18:10 ` Stefan.Lucks 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-06 7:39 UTC (permalink / raw) On Fri, 5 Apr 2013 22:23:13 +0200, Stefan.Lucks@uni-weimar.de wrote: > On Fri, 5 Apr 2013, Dmitry A. Kazakov wrote: > >> On Fri, 5 Apr 2013 21:02:43 +0200, Stefan.Lucks@uni-weimar.de wrote: > >> No, I insist that it is up to the programmer to decide whether two types to >> become compatible (relative) or not. Character and Wide_Character are >> evidently relative. > > Integer and Float are "evidently relative". No, as I said it is in the application domain. If your domain were mathematical analysis then, yes, integer and float would be related. When the domain is engineering they are clearly not, because in that domain as well as in most other domains, number is used not as number, but as an object modeling something else. >> I disagree. They wanted to prevent the mess of PL/1 where *arbitrary* >> conversions were applied to semantically unrelated types. Types like >> Character and Wide_Character are semantically related. Conversion from one >> to another is perfectly well defined. > > The same for conversions between Integer and Float. Nope. You cannot convert house number to outdoor temperature. >> And it is all up to the programmer to tell the compiler that S must be >> considered a subtype of T, whatever representation both might have is not >> language's business. > > Arithmetic types and String types are in the same boat here. String types are not models when we consider major use cases for String/Wide_String/Wide_Wide_String. They are entities from one domain meaning same entities [domain: Unicode]. Certainly there are cases when strings can be used to model something else. But it is highly unlikely that they would distinguish String and Wide_String either. Numbers are clearly different, e.g. counting apples and oranges [domain: grocery] -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-06 7:39 ` Dmitry A. Kazakov @ 2013-04-07 18:10 ` Stefan.Lucks 2013-04-07 18:23 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Stefan.Lucks @ 2013-04-07 18:10 UTC (permalink / raw) [-- Attachment #1: Type: TEXT/PLAIN, Size: 1650 bytes --] On Sat, 6 Apr 2013, Dmitry A. Kazakov wrote: >> The same for conversions between Integer and Float. > > Nope. You cannot convert house number to outdoor temperature. So what? Neither can I convert my zip code to my birth year (both Positive) or the outdoor temperature to speed of light. ;-) Ada allows to define types such as, Apples and Oranges, or, say Speed and Temperature. But this has nothing to do with the underlying mathematical struture of each of these types. Actually, mixing integers and float (or integers and fixed-point numbers) is not that uncommon. The maximum speed for a vehicle, say, a train at a certain part of the track, is, most likely, an integer, while the speed the sensors measure isn't an integer. So you have something like the following code: Current_Speed : Speed; Max_Speed : Integer_Speed; Safety_Margin : constant Speed := ... ... if Current_Speed > Speed(Max_Speed) then Display_Warning(Speed_Warning); Play_Alarm_Sound; if Current_Speed < (Speed(Max_Speed) + Safety_Margin) then Perform_Emergency_Break; end_if: end_if; Here, you need the to convert Max_Speed to Speed, even though the two types Speed and Integer_Speed have the same semantic. I don't think we'll agree on this issue, but I fail to see any significant distinction between the class of arithmetic types and string types. ------ I love the taste of Cryptanalysis in the morning! ------ <http://www.uni-weimar.de/cms/medien/mediensicherheit/home.html> --Stefan.Lucks (at) uni-weimar.de, Bauhaus-Universität Weimar, Germany-- ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-07 18:10 ` Stefan.Lucks @ 2013-04-07 18:23 ` Dmitry A. Kazakov 0 siblings, 0 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-07 18:23 UTC (permalink / raw) On Sun, 7 Apr 2013 20:10:09 +0200, Stefan.Lucks@uni-weimar.de wrote: > On Sat, 6 Apr 2013, Dmitry A. Kazakov wrote: > >>> The same for conversions between Integer and Float. >> >> Nope. You cannot convert house number to outdoor temperature. > > So what? Neither can I convert my zip code to my birth year (both > Positive) or the outdoor temperature to speed of light. ;-) Which is the whole point. > I don't think we'll agree on this issue, but I fail to see any significant > distinction between the class of arithmetic types and string types. The distinction is one domain vs. many. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-05 19:34 ` Dmitry A. Kazakov 2013-04-05 20:23 ` Stefan.Lucks @ 2013-04-05 20:38 ` Stefan.Lucks 1 sibling, 0 replies; 242+ messages in thread From: Stefan.Lucks @ 2013-04-05 20:38 UTC (permalink / raw) [-- Attachment #1: Type: TEXT/PLAIN, Size: 1573 bytes --] On Fri, 5 Apr 2013, Dmitry A. Kazakov wrote: > We are discussing deficiencies of Ada type system, unable to capture > relations between domain specific entities modeled as objects and types. Well, that is a broader discussion than the part I was in, that was about the need for some Universal_String type, but OK. > E.g. few built-in numeric types, which are supposed to fit everything and > expectedly fail, because predefined numbers have properties you might not > need and miss ones you do need. The Op's subtype Prim was a perfect example > of such a failure. Prime numbers are neither additive nor multiplicative. > It is not a group. Yet Prime inherited the interface of a group from base > type (Positive) and there is no way to prohibit this. It also inherited the > order of Positives ('Succ), which is not one of Prime, and, again, there is > no language means for fix that. Here, I have agree with you. I understand that for historical reasons Prime'Succ is actually Prime'Base'Succ, and the designers of Ada 2012 have unable to get rid of that without introducing too many incompatibilities. But Prime'Succ(5)=4 is a big OUCH! I hope that Ada 2020 (or whatever) will prohibit the attibutes Succ and Pred for all subtypes with dynamic predicates! (I think, First and Last are prohibited anyway.) ------ I love the taste of Cryptanalysis in the morning! ------ <http://www.uni-weimar.de/cms/medien/mediensicherheit/home.html> --Stefan.Lucks (at) uni-weimar.de, Bauhaus-Universität Weimar, Germany-- ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-05 12:45 ` Stefan.Lucks 2013-04-05 12:49 ` Stefan.Lucks @ 2013-04-05 14:36 ` Dmitry A. Kazakov 2013-04-05 15:16 ` Stefan.Lucks 1 sibling, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-05 14:36 UTC (permalink / raw) On Fri, 5 Apr 2013 14:45:55 +0200, Stefan.Lucks@uni-weimar.de wrote: > But what reasons would you have to actually mix > narrow, Wide_ and Wide_Wide_ Strings? What is at least one reason to distinguish them? Once answered, please name a reason to distinguish UTF-16, UTF-8, UCS-2 etc strings in assignment, comparison, concatenation. There is none. Ugly design of Unbounded_String proved that. All differences are motivated by implementation details and related to the string origin or its consumer. Semantically all strings are nothing but sequences of code points. And, again, it is already *mixed* in Ada. "abc" is overloaded String, Wide_String, Wide_Wide_String. Furthermore, very idea of new string design is to mix it even more than it was before in order to get rid of the mess of I/O package multiplying like cockroaches. The difference between Randy and me, is that he wants to scrap all operations Ada 83 strings had. Since this would be clearly incompatible with existing programs, he wants to add them as completely new types, as if we had not enough string types in the language already. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-05 14:36 ` Dmitry A. Kazakov @ 2013-04-05 15:16 ` Stefan.Lucks 2013-04-05 16:29 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Stefan.Lucks @ 2013-04-05 15:16 UTC (permalink / raw) [-- Attachment #1: Type: TEXT/PLAIN, Size: 1816 bytes --] On Fri, 5 Apr 2013, Dmitry A. Kazakov wrote: > On Fri, 5 Apr 2013 14:45:55 +0200, Stefan.Lucks@uni-weimar.de wrote: > >> But what reasons would you have to actually mix >> narrow, Wide_ and Wide_Wide_ Strings? > > What is at least one reason to distinguish them? I agree with you that there is no reason to distinguish between them. The entire distinction narrow, Wide_ and Wide_Wide_ Strings (and Characters) is a historical artifact, no more, no less. But if there is no reason to disting between them -- there is no reason to mix them either! Right now, the best you can do if you really have to use different of these String types is the following: 1. convert everything into a single type (probably Wide_Wide_String), 2. do your work. 3. and convert back (if you really have to). > Once answered, please name a reason to distinguish UTF-16, UTF-8, UCS-2 etc > strings in assignment, comparison, concatenation. I agree, there is none. Which is precicely why one should not need any mixed-representation operations. > The difference between Randy and me, is that he wants to scrap all > operations Ada 83 strings had. Since this would be clearly incompatible > with existing programs, he wants to add them as completely new types, as if > we had not enough string types in the language already. I think, I agree with Randy here. The old bunch of strings are a mess, that has historically evolved and is far beyond repair. Trying to repair it by adding support for mixed operations gives birth to a gazillion of new cockroaches. ------ I love the taste of Cryptanalysis in the morning! ------ <http://www.uni-weimar.de/cms/medien/mediensicherheit/home.html> --Stefan.Lucks (at) uni-weimar.de, Bauhaus-Universität Weimar, Germany-- ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-05 15:16 ` Stefan.Lucks @ 2013-04-05 16:29 ` Dmitry A. Kazakov 2013-04-05 19:55 ` Stefan.Lucks 2013-04-06 1:38 ` Randy Brukardt 0 siblings, 2 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-05 16:29 UTC (permalink / raw) On Fri, 5 Apr 2013 17:16:59 +0200, Stefan.Lucks@uni-weimar.de wrote: > On Fri, 5 Apr 2013, Dmitry A. Kazakov wrote: > >> On Fri, 5 Apr 2013 14:45:55 +0200, Stefan.Lucks@uni-weimar.de wrote: >> >>> But what reasons would you have to actually mix >>> narrow, Wide_ and Wide_Wide_ Strings? >> >> What is at least one reason to distinguish them? > > I agree with you that there is no reason to distinguish between them. The > entire distinction narrow, Wide_ and Wide_Wide_ Strings (and Characters) > is a historical artifact, no more, no less. > > But if there is no reason to disting between them -- there is no reason to > mix them either! Sorry, but it cannot be both. > Right now, the best you can do if you really have to use different of > these String types is the following: > 1. convert everything into a single type (probably Wide_Wide_String), > 2. do your work. > 3. and convert back (if you really have to). This is how the compiler could implement the interface inherited from the root string type, e.g. from Wide_Wide_String. But that is an implementation detail. The problem is in resolution of mixed operations *inevitably* emerging from putting strings under the same roof. Wether you inherit an implementation from Wide_Wide_String and compose it with a conversion forth and/or back to String or else override it with a tailored implementation is not the core problem. The problem is that Ada does not support multi-methods needed for this. That literals generate uncontrollable ambiguities. These problems are to address. >> Once answered, please name a reason to distinguish UTF-16, UTF-8, UCS-2 etc >> strings in assignment, comparison, concatenation. > > I agree, there is none. Which is precicely why one should not need any > mixed-representation operations. How so? Apart from comparisons and concatenation. Consider Ada.Text_IO.Create. It has name a string and content. You tell us that it is not necessary to be able to open an UTF-8 file which name is UTF-16? Blame Microsoft. >> The difference between Randy and me, is that he wants to scrap all >> operations Ada 83 strings had. Since this would be clearly incompatible >> with existing programs, he wants to add them as completely new types, as if >> we had not enough string types in the language already. > > I think, I agree with Randy here. The old bunch of strings are a mess, There is nothing wrong with them except for being not in the same class. [Literals could be done better] > that has historically evolved and is far beyond repair. Trying to repair > it by adding support for mixed operations gives birth to a gazillion of > new cockroaches. They tried once, see Unbounded_String. They tried twice, see bounded strings. This is an inherently flawed approach. Furthermore what Randy proposes will actually be worse than pitiful Unbounded_String. For them you could at least do this: type Relative_File_Path is new Unbounded_String; type Absolute_File_Path is new Unbounded_String; You could not do that for tagged strings. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-05 16:29 ` Dmitry A. Kazakov @ 2013-04-05 19:55 ` Stefan.Lucks 2013-04-06 1:45 ` Randy Brukardt 2013-04-06 7:54 ` Dmitry A. Kazakov 2013-04-06 1:38 ` Randy Brukardt 1 sibling, 2 replies; 242+ messages in thread From: Stefan.Lucks @ 2013-04-05 19:55 UTC (permalink / raw) [-- Attachment #1: Type: TEXT/PLAIN, Size: 4534 bytes --] On Fri, 5 Apr 2013, Dmitry A. Kazakov wrote: > On Fri, 5 Apr 2013 17:16:59 +0200, Stefan.Lucks@uni-weimar.de wrote: >> I agree with you that there is no reason to distinguish between them. The >> entire distinction narrow, Wide_ and Wide_Wide_ Strings (and Characters) >> is a historical artifact, no more, no less. >> >> But if there is no reason to disting between them -- there is no reason to >> mix them either! > > Sorry, but it cannot be both. No, if you mix them, you must distinguish them. At least, when implementing your own multi-method, such as function Longest_Common_Substring(S1, S2: Universal_String) return Universal_String; -- maybe "is abstract"; Either Universal_String is abstract, then so would be this multi-method, and you would to override it n^3 times, when supporting n different string types. Or you can actually have objects of type Universal_String, but then using this method without making explicit conversions means a whole new bunch of implicit conversions. One problem with implicit conversions is that Strings don't "know" their encoding (Is it UTF-8? Or ISO-Latin-1? Or ...?), so you don't even have the information you need to perform the conversion. Which is why you need to make explicit conversions. And then it is not a big leap to say "convert everything into my favourite kind of string, then call my method, and then convert the result back". > Consider Ada.Text_IO.Create. It has name a string and content. You tell > us that it is not necessary to be able to open an UTF-8 file which name > is UTF-16? Blame Microsoft. I know a lot of things to blame Microsoft for, but in the Unix world, all files are essentially sequences of bytes that you read or write, and it is your problem to know the semantic of these sequences. So this is not much better than in the Microsoft world. In any case, Ada.Text_IO.Create is a good example. As much as I understand you, if Name is of type Universal_String'Class and you call Ada.Text_IO.Create(File, Name) you expect the proper thing to happen, right? I agree that this would be cool. But it just cannot work! Right now, if the encoding of Name is, say, ISO-Latin-1 and the encoding the underlying filesystem expects is UTF-8, you can have really surprising results when calling Ada.Text_IO.Create(File, Name). It would be cool to solve this issue with some Universal_String type. But firstly, the strings we have don't know their encoding. The application programmer knows (hopefully), but it is not part of String. Secondly, even if we had some kind of enhanced string type with object Name storing its own encoding, in addition to the string itself, the library wouldn't know which encoding it to convert Name into, or if any conversion is needed at all! The point is, you can mount different filesystems with different naming and encoding conventions, even on the same machine. (With Linux for sure, I guess that also works in the Microsoft world.) No Universal_ type will solve this issue -- you just cannot get rid of explicit conversions. At the end of the day, something such as opening or creating a file is some kind of a low-level operation, alas. >> I think, I agree with Randy here. The old bunch of strings are a mess, > > There is nothing wrong with them except for being not in the same class. > [Literals could be done better] > Furthermore what Randy proposes will actually be worse than pitiful > Unbounded_String. For them you could at least do this: > > type Relative_File_Path is new Unbounded_String; > type Absolute_File_Path is new Unbounded_String; > > You could not do that for tagged strings. OK, here we agree. Whatever the "new" strings are, the ability to define incompatible types with the same representation, that you cannot mix (without explicit conversion) is important for a language supporting safety-critical stuff! I sometimes have types Tainted_String and Save_String, being both derived from [Wide_[Wide_]]String, and I am happy when the compiler stops me from messing up between variables of this type. Does Randy's proposal really not allow that? ------ I love the taste of Cryptanalysis in the morning! ------ <http://www.uni-weimar.de/cms/medien/mediensicherheit/home.html> --Stefan.Lucks (at) uni-weimar.de, Bauhaus-Universität Weimar, Germany-- ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-05 19:55 ` Stefan.Lucks @ 2013-04-06 1:45 ` Randy Brukardt 2013-04-06 7:54 ` Dmitry A. Kazakov 1 sibling, 0 replies; 242+ messages in thread From: Randy Brukardt @ 2013-04-06 1:45 UTC (permalink / raw) <Stefan.Lucks@uni-weimar.de> wrote in message news:alpine.DEB.2.02.1304052103590.31746@debian... ... >OK, here we agree. Whatever the "new" strings are, the ability to define >incompatible types with the same representation, that you cannot mix >(without explicit conversion) is important for a language supporting >safety-critical stuff! I sometimes have types Tainted_String and >Save_String, being both derived from [Wide_[Wide_]]String, and I am happy >when the compiler stops me from messing up between variables of this type. >Does Randy's proposal really not allow that? Of course they're different types. They wouldn't be mixable amongst themselves (Dmitry's obcession with multi-methods would of course erode any such protections). They both would implicitly convert to Root_String'Class, of course, and there wouldn't be any way to prevent that. But I can't see any particular new problem with this, you have the same effect for any Ada tagged type and associated class-wide type. I know Dmitry would like to have some sort of way to split off clones of types that are completely incompatible, but that would have severe consequences with the other uses for type hierarchies (conversions and formal types), as those could not be allowed either. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-05 19:55 ` Stefan.Lucks 2013-04-06 1:45 ` Randy Brukardt @ 2013-04-06 7:54 ` Dmitry A. Kazakov 2013-04-07 18:17 ` Stefan.Lucks 1 sibling, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-06 7:54 UTC (permalink / raw) On Fri, 5 Apr 2013 21:55:27 +0200, Stefan.Lucks@uni-weimar.de wrote: > On Fri, 5 Apr 2013, Dmitry A. Kazakov wrote: > >> On Fri, 5 Apr 2013 17:16:59 +0200, Stefan.Lucks@uni-weimar.de wrote: > >>> I agree with you that there is no reason to distinguish between them. The >>> entire distinction narrow, Wide_ and Wide_Wide_ Strings (and Characters) >>> is a historical artifact, no more, no less. >>> >>> But if there is no reason to disting between them -- there is no reason to >>> mix them either! >> >> Sorry, but it cannot be both. > > No, if you mix them, you must distinguish them. At least, when > implementing your own multi-method, such as > > function Longest_Common_Substring(S1, S2: Universal_String) > return Universal_String; > -- maybe "is abstract"; > > Either Universal_String is abstract, then so would be this multi-method, > and you would to override it n^3 times, when supporting n different string > types. You could inherit it per composition with conversion [the language should support this sort of delegation]. > Or you can actually have objects of type Universal_String, but then > using this method without making explicit conversions means a whole new > bunch of implicit conversions. Actually there are more than 2 alternatives. Either argument and/or result can covariant or contravariant. > One problem with implicit conversions is that Strings don't "know" their > encoding (Is it UTF-8? Or ISO-Latin-1? Or ...?), so you don't even have > the information you need to perform the conversion. The space of related types is at least 3D: 1. One hierarchy follows the hierarchy of characters: Wide_Wide_Character :> Wide_Character :> Character :> ASCII_Character + EBCDIC_Character etc. 2. Another hierarchy is about constrained vs. unbounded strings 3. The third hierarchy encompasses encoding. For each two points in this space it is perfectly clear how to convert one to another. > Which is why you need to make explicit conversions. There is no need in explicit conversions because it is well defined how to obtain one string from another. > And then it is not a big leap to say "convert everything into my favourite > kind of string, then call my method, and then convert the result back". This one possible implementation. Once you have a mesh of related types you can define specific bodies for interesting combinations of arguments and leave other generated per composition with conversion. >> Consider Ada.Text_IO.Create. It has name a string and content. You tell >> us that it is not necessary to be able to open an UTF-8 file which name >> is UTF-16? Blame Microsoft. > > I know a lot of things to blame Microsoft for, but in the Unix world, all > files are essentially sequences of bytes that you read or write, and it is > your problem to know the semantic of these sequences. Which is why you need a Text_IO package for each combination content encoding x name encoding. > In any case, Ada.Text_IO.Create is a good example. > > As much as I understand you, if Name is of type Universal_String'Class and > you call Ada.Text_IO.Create(File, Name) you expect the proper thing to > happen, right? I meant two arguments: Name => some string type Form => some encoding of the content as an example when different string types must be mixed. Under MS Windows so called W-calls use UTF-16 encoded names, while the file content could be anything, e.g. UTF-8. You can guess how many combinations exist. > But firstly, the strings we have don't know their encoding. They know. See 3.5.2 which defines character set. Yes, some people including me use String for UTF-8 and Wide_String for UTF-16. This is clearly wrong. UTF-8 string is equivalent to Wide_Wide_String and cannot be reinterpreted as String. > No Universal_ type will solve this issue -- you just cannot get rid of > explicit conversions. You can. Actually, what people do right now is implicit unchecked conversions from UTF-8 to String. It is even worse than PL/1, it is plain wrong, C-esque of worst kind. Unfortunately Ada simply offers no means to design it right. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-06 7:54 ` Dmitry A. Kazakov @ 2013-04-07 18:17 ` Stefan.Lucks 2013-04-07 18:28 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Stefan.Lucks @ 2013-04-07 18:17 UTC (permalink / raw) [-- Attachment #1: Type: TEXT/PLAIN, Size: 1121 bytes --] On Sat, 6 Apr 2013, Dmitry A. Kazakov wrote: > On Fri, 5 Apr 2013 21:55:27 +0200, Stefan.Lucks@uni-weimar.de wrote: >> In any case, Ada.Text_IO.Create is a good example. [...] >> No Universal_ type will solve this issue -- you just cannot get rid of >> explicit conversions. > > You can. Actually, what people do right now is implicit unchecked > conversions from UTF-8 to String. It is even worse than PL/1, it is plain > wrong, C-esque of worst kind. Unfortunately Ada simply offers no means to > design it right. If you have mounted different filesystems using different encodings on your system, how on earth should Ada.Text_IO even "know" which encoding to apply? (And even if not, how would Ada.Text_IO "know" the proper encoding?) Yes, this is C-esque of the worst kine. However, what would you expect when making system calls with operation systems written in C? ------ I love the taste of Cryptanalysis in the morning! ------ <http://www.uni-weimar.de/cms/medien/mediensicherheit/home.html> --Stefan.Lucks (at) uni-weimar.de, Bauhaus-Universität Weimar, Germany-- ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-07 18:17 ` Stefan.Lucks @ 2013-04-07 18:28 ` Dmitry A. Kazakov 2013-04-08 7:48 ` Stefan.Lucks 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-07 18:28 UTC (permalink / raw) On Sun, 7 Apr 2013 20:17:43 +0200, Stefan.Lucks@uni-weimar.de wrote: > On Sat, 6 Apr 2013, Dmitry A. Kazakov wrote: > >> On Fri, 5 Apr 2013 21:55:27 +0200, Stefan.Lucks@uni-weimar.de wrote: > >>> In any case, Ada.Text_IO.Create is a good example. > [...] >>> No Universal_ type will solve this issue -- you just cannot get rid of >>> explicit conversions. >> >> You can. Actually, what people do right now is implicit unchecked >> conversions from UTF-8 to String. It is even worse than PL/1, it is plain >> wrong, C-esque of worst kind. Unfortunately Ada simply offers no means to >> design it right. > > If you have mounted different filesystems using different encodings on > your system, how on earth should Ada.Text_IO even "know" which encoding to > apply? How is this relevant to the issue that encoding must a part of the type? > Yes, this is C-esque of the worst kine. However, what would you expect > when making system calls with operation systems written in C? I expect the type system to handle equivalent types of different representations such as UTF-8 and UCS-4 strings. As it already does in the case Universal_Integer vs. Integer. Both are distinct types, both have different representations, both are considered equivalent in certain cases. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-07 18:28 ` Dmitry A. Kazakov @ 2013-04-08 7:48 ` Stefan.Lucks 2013-04-08 8:59 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Stefan.Lucks @ 2013-04-08 7:48 UTC (permalink / raw) On Sun, 7 Apr 2013, Dmitry A. Kazakov wrote: >> If you have mounted different filesystems using different encodings on >> your system, how on earth should Ada.Text_IO even "know" which encoding to >> apply? > > How is this relevant to the issue that encoding must a part of the type? Because even if the implementation of Ada.Text_IO.Open would know the encoding of the filename, it could do nothing useful with it. >> Yes, this is C-esque of the worst kine. However, what would you expect >> when making system calls with operation systems written in C? > > I expect the type system to handle equivalent types of different > representations such as UTF-8 and UCS-4 strings. As it already does in the > case Universal_Integer vs. Integer. Both are distinct types, both have > different representations, both are considered equivalent in certain cases. Universal_Integer is a pseudo-type. You cannot define an object O: Universal_Integer, neither a function returning Universal_Integer ... The only thing that Universal_Integer handles well is a neat way of defining constants. The mess with the different string types in Ada is not just about string constants, it goes much beyond. ------ I love the taste of Cryptanalysis in the morning! ------ <http://www.uni-weimar.de/cms/medien/mediensicherheit/home.html> --Stefan.Lucks (at) uni-weimar.de, Bauhaus-Universität Weimar, Germany-- ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-08 7:48 ` Stefan.Lucks @ 2013-04-08 8:59 ` Dmitry A. Kazakov 2013-04-08 15:35 ` Stefan.Lucks 2013-04-09 22:45 ` Randy Brukardt 0 siblings, 2 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-08 8:59 UTC (permalink / raw) On Mon, 8 Apr 2013 09:48:07 +0200, Stefan.Lucks@uni-weimar.de wrote: > On Sun, 7 Apr 2013, Dmitry A. Kazakov wrote: > >>> If you have mounted different filesystems using different encodings on >>> your system, how on earth should Ada.Text_IO even "know" which encoding to >>> apply? >> >> How is this relevant to the issue that encoding must a part of the type? > > Because even if the implementation of Ada.Text_IO.Open would know the > encoding of the filename, it could do nothing useful with it. ??? It must know the encoding in order to handle the file properly. >>> Yes, this is C-esque of the worst kine. However, what would you expect >>> when making system calls with operation systems written in C? >> >> I expect the type system to handle equivalent types of different >> representations such as UTF-8 and UCS-4 strings. As it already does in the >> case Universal_Integer vs. Integer. Both are distinct types, both have >> different representations, both are considered equivalent in certain cases. > > Universal_Integer is a pseudo-type. With pseudo-values and pseudo-operations used by pseudo-programmers? (:-)) > You cannot define an object O: > Universal_Integer, neither a function returning Universal_Integer ... As if it were relevant. But you are wrong here. Universal types leak into run time through attributes. I.e. you do have objects of universal types at run time in expressions like Integer'Pos (X) * 2 > The only thing that Universal_Integer handles well is a neat way of > defining constants. That is the whole point. It is already here, because it is needed. > The mess with the different string types in Ada is not > just about string constants, it goes much beyond. That is the reason why it should be fixed. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-08 8:59 ` Dmitry A. Kazakov @ 2013-04-08 15:35 ` Stefan.Lucks 2013-04-08 19:08 ` Dmitry A. Kazakov 2013-04-09 22:53 ` Is this expected behavior or not Randy Brukardt 2013-04-09 22:45 ` Randy Brukardt 1 sibling, 2 replies; 242+ messages in thread From: Stefan.Lucks @ 2013-04-08 15:35 UTC (permalink / raw) On Mon, 8 Apr 2013, Dmitry A. Kazakov wrote: >> Because even if the implementation of Ada.Text_IO.Open would know the >> encoding of the filename, it could do nothing useful with it. > > ??? It must know the encoding in order to handle the file properly. Ah! Finally you seem to understand where the problem is! Ada.Text_IO would have to know the encoding, but it doesn't. So it just treats the string like a sequence of bytes (much like a C-string) and leaves it to the Application Programmer to apply the proper conversion before. Which means, the conversion must be done explicitly. >> Universal_Integer is a pseudo-type. > > With pseudo-values and pseudo-operations used by pseudo-programmers? (:-)) All objects of that type are constant. All operations are evaluated at compile time. Whenever values of this type make it into run-time objects, they magically change their type. >> You cannot define an object O: >> Universal_Integer, neither a function returning Universal_Integer ... > > As if it were relevant. But you are wrong here. How so? > Universal types leak into > run time through attributes. I.e. you do have objects of universal types at > run time in expressions like > > Integer'Pos (X) * 2 You just used the already existing object 2 of type constant Universal_Integer. Even if you ignore the "constant", there is no *definition* (or *declaration*) of an object O: Universal_Integer. >> The only thing that Universal_Integer handles well is a neat way of >> defining constants. > > That is the whole point. It is already here, because it is needed. I see. Some pseudo-type Universal_String might possibly help with string constants (I am not sure -- it is much more difficult to figure out the proper transformation to whatever string type you really need). But the mess with string types in Ada goes deeper, and Universal_Strings would at best solve half of the problem. YMMV, but I'd say much less than half of the problem. ------ I love the taste of Cryptanalysis in the morning! ------ <http://www.uni-weimar.de/cms/medien/mediensicherheit/home.html> --Stefan.Lucks (at) uni-weimar.de, Bauhaus-Universität Weimar, Germany-- ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-08 15:35 ` Stefan.Lucks @ 2013-04-08 19:08 ` Dmitry A. Kazakov 2013-04-09 7:18 ` Stefan.Lucks 2013-04-09 22:53 ` Is this expected behavior or not Randy Brukardt 1 sibling, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-08 19:08 UTC (permalink / raw) On Mon, 8 Apr 2013 17:35:17 +0200, Stefan.Lucks@uni-weimar.de wrote: > On Mon, 8 Apr 2013, Dmitry A. Kazakov wrote: > >>> Because even if the implementation of Ada.Text_IO.Open would know the >>> encoding of the filename, it could do nothing useful with it. >> >> ??? It must know the encoding in order to handle the file properly. > > Ah! Finally you seem to understand where the problem is! > > Ada.Text_IO would have to know the encoding, but it doesn't. See s-fileio.adb, lines 845-857. >>> Universal_Integer is a pseudo-type. >> >> With pseudo-values and pseudo-operations used by pseudo-programmers? (:-)) > > All objects of that type are constant. All operations are evaluated at > compile time. This is wrong. See 3.5.5(2) as an example of a non-static function returning Universal_Integer. That Universal_Integer leaks allows writing quite strange programs, e.g. ones using 'Pos attribute in order to perform run-time computations in universal arithmetic. Beware, that this is not portable, of course. Universal integer is constrained at run time. >> Universal types leak into >> run time through attributes. I.e. you do have objects of universal types at >> run time in expressions like >> >> Integer'Pos (X) * 2 > > You just used the already existing object 2 of type constant > Universal_Integer. Integer'Pos (X) * Integer'Pos (Y) > Even if you ignore the "constant", there is no > *definition* (or *declaration*) of an object O: Universal_Integer. Universal_Integer and other numeric types can be mixed in arithmetic and other operations. Period. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-08 19:08 ` Dmitry A. Kazakov @ 2013-04-09 7:18 ` Stefan.Lucks 2013-04-09 8:17 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Stefan.Lucks @ 2013-04-09 7:18 UTC (permalink / raw) On Mon, 8 Apr 2013, Dmitry A. Kazakov wrote: >> Ada.Text_IO would have to know the encoding, but it doesn't. > > See s-fileio.adb, lines 845-857. Cool! I haven't been aware of that. Starting with line 483: if V1 = 0 then Encoding := CRTL.Unspecified; elsif Formstr (V1 .. V2) = "utf8" then Encoding := CRTL.UTF8; elsif Formstr (V1 .. V2) = "8bits" then Encoding := CRTL.ASCII_8bits; else raise Use_Error with "invalid Form"; end if; So the GNAT implementation of Ada.Text_IO can distinguish between Unspecified, UTF8 and ASCII-8bits. This is more than I would have expected. But it not really useful. Apart from the portability issue (what are the standard libs of other compilers doing?), there are a hell of different encodings your filesystem might use. There is old CP437 from MS-DOS time, there are more than ten different ISO 8859 encodings, ... A special technical issue is that the encoding of the fully qualified filename can change even *within* the string itself -- the first part of the path is using the encoding of the root filesystem, while the rest uses the encoding of the filesystem itself. In practice, this is mostly harmless, since the first part typically looks like "/media/disk/" or "/dev/sdb5", using only characters which are invariant under most common encodings. But this still shows that the idea of letting Ada.Text_IO dealing with the encoding will get you only so far. >> compile time. > > This is wrong. See 3.5.5(2) as an example of a non-static function > returning Universal_Integer. Well, the authors of the standard can use "standard definition magic" to define such a function, but the author of an Ada program cannot. There is no type with name Universal_Integer in Ada programs, and any attempt to define one will, at best, overload the name of Universal_Integer, but never give you the type that the standard denotes as Universal_Integer. >> You just used the already existing object 2 of type constant >> Universal_Integer. > > Integer'Pos (X) * Integer'Pos (Y) Language lawyers may correct me, but if X and Y are not static, I would expect Integer'Pos(X) and Integer'Pos(Y) to be converted to the expected result type even before the multiplication has been called. > Universal_Integer and other numeric types can be mixed in arithmetic and > other operations. Period. Again, my understanding is that they are converted before any run-time operation is performed. ------ I love the taste of Cryptanalysis in the morning! ------ <http://www.uni-weimar.de/cms/medien/mediensicherheit/home.html> --Stefan.Lucks (at) uni-weimar.de, Bauhaus-Universität Weimar, Germany-- ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-09 7:18 ` Stefan.Lucks @ 2013-04-09 8:17 ` Dmitry A. Kazakov 2013-04-09 15:20 ` Stefan.Lucks 2013-04-09 22:57 ` Randy Brukardt 0 siblings, 2 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-09 8:17 UTC (permalink / raw) On Tue, 9 Apr 2013 09:18:09 +0200, Stefan.Lucks@uni-weimar.de wrote: > On Mon, 8 Apr 2013, Dmitry A. Kazakov wrote: > >>> Ada.Text_IO would have to know the encoding, but it doesn't. >> >> See s-fileio.adb, lines 845-857. > > Cool! I haven't been aware of that. Starting with line 483: > > if V1 = 0 then > Encoding := CRTL.Unspecified; > > elsif Formstr (V1 .. V2) = "utf8" then > Encoding := CRTL.UTF8; > > elsif Formstr (V1 .. V2) = "8bits" then > Encoding := CRTL.ASCII_8bits; > > else > raise Use_Error with "invalid Form"; > end if; > > So the GNAT implementation of Ada.Text_IO can distinguish between > Unspecified, UTF8 and ASCII-8bits. This is more than I would have > expected. But it not really useful. Of course it is useful because text files have different encoding. > Apart from the portability issue (what > are the standard libs of other compilers doing?), there are a hell of > different encodings your filesystem might use. There is old CP437 from > MS-DOS time, there are more than ten different ISO 8859 encodings, ... This is why string types SHALL be designed properly in order to handle this without introducing millions of I/O packages. > A special technical issue is that the encoding of the fully qualified > filename can change even *within* the string itself -- the first part of > the path is using the encoding of the root filesystem, while the rest uses > the encoding of the filesystem itself. File name is not a string in first place. Ada.Directory and other I/O packages are broken in that respect, but that is irrelevant here. >>> compile time. >> >> This is wrong. See 3.5.5(2) as an example of a non-static function >> returning Universal_Integer. > > Well, the authors of the standard can use "standard definition magic" to > define such a function, but the author of an Ada program cannot. You cannot do X : String; either. String is a pseudo-type? Is it RM terminology? (:-)) Now consider Ada.Strings.Unbounded. It has a whole lot of mixed string type operation declared: Append, "&", "=", "<", ">", ">=", "<=". Now as we learned that String is "pseudo-type," it would be OK to mix. Right? But then, what is the buzz? If string types are pseudo-type we can mix them happily anyway! (:-)) >>> You just used the already existing object 2 of type constant >>> Universal_Integer. >> >> Integer'Pos (X) * Integer'Pos (Y) > > Language lawyers may correct me, but if X and Y are not static, I would > expect Integer'Pos(X) and Integer'Pos(Y) to be converted to the expected > result type even before the multiplication has been called. Character'Val (Integer'Pos (X) * Long_Integer'Pos (Y)) >> Universal_Integer and other numeric types can be mixed in arithmetic and >> other operations. Period. > > Again, my understanding is that they are converted before any run-time > operation is performed. Wrong but irrelevant as well, because semantically there is no difference. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-09 8:17 ` Dmitry A. Kazakov @ 2013-04-09 15:20 ` Stefan.Lucks 2013-04-09 16:15 ` Dmitry A. Kazakov 2013-04-09 22:59 ` Randy Brukardt 2013-04-09 22:57 ` Randy Brukardt 1 sibling, 2 replies; 242+ messages in thread From: Stefan.Lucks @ 2013-04-09 15:20 UTC (permalink / raw) On Tue, 9 Apr 2013, Dmitry A. Kazakov wrote: > This is why string types SHALL be designed properly in order to handle this > without introducing millions of I/O packages. We are in violent agreement here. The question is how much compatibility is needed between a new string type and the gazillions of old and broken ones, not that strings SHOULD be designed properly ... > File name is not a string in first place. Ada.Directory and other I/O > packages are broken in that respect, but that is irrelevant here. It was you who came up with the example of Ada.Text_IO.Open, not me. > You cannot do > > X : String; > > either. String is a pseudo-type? This is a straw man argument. String is not pseudo. As you know very well, you can do X: String := ... or X: String(A ..B), while you can't do anything similar for Universal_Integer. >> Again, my understanding is that they are converted before any run-time >> operation is performed. > > Wrong but irrelevant as well, because semantically there is no difference. OK, so look at the semantic. Different semantic means the same operation with the same inputs behave differently. The following program fragment nicely prints "Smaller or Equal": if ((Character'Pos('z') ** Character'Pos('z')) > (Character'Pos('z') ** Character'Pos('z'))) then Put_Line("Larger"); else Put_Line("Smaller or Equal"); end if; This is really cool -- the sematic of Universal_Integer enables us to perform operations over huge integers without overflows. Now, guess what the following program fragment does? S: String := "zzzz"; begin if ((Character'Pos(S(1)) ** Character'Pos(S(3))) > (Character'Pos(S(2)) ** Character'Pos(S(4)))) then Put_Line("More"); else Put_Line("Less or Equal"); end if; The output is neither "More" nor "Less or Equal" but "raised CONSTRAINT_ERROR : arit64.c:52 overflow check failed". (When using gnat, don't forget "-gnato" to switch on overflow checks.) Whenever the compiler cannot statically evaluate expressions of type Universal_Integer it switches to run time arithmetic over some integer type available at run time. This means, the expression behaves according to that type's semantic, raising Constraint_Error on overflows included. If you insist that all the operations (such as the "**") above are over Universal_Integer, than that would mean the semantic of Universal_Integer is allowed to change, depending on compile. versus run time. That would be even more "pseudo". ;-) ------ I love the taste of Cryptanalysis in the morning! ------ <http://www.uni-weimar.de/cms/medien/mediensicherheit/home.html> --Stefan.Lucks (at) uni-weimar.de, Bauhaus-Universität Weimar, Germany-- ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-09 15:20 ` Stefan.Lucks @ 2013-04-09 16:15 ` Dmitry A. Kazakov 2013-04-09 22:59 ` Randy Brukardt 1 sibling, 0 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-09 16:15 UTC (permalink / raw) On Tue, 9 Apr 2013 17:20:35 +0200, Stefan.Lucks@uni-weimar.de wrote: > On Tue, 9 Apr 2013, Dmitry A. Kazakov wrote: > >> You cannot do >> >> X : String; >> >> either. String is a pseudo-type? > > This is a straw man argument. String is not pseudo. Universal_Integer is neither. >>> Again, my understanding is that they are converted before any run-time >>> operation is performed. >> >> Wrong but irrelevant as well, because semantically there is no difference. > > OK, so look at the semantic. Different semantic means the same operation > with the same inputs behave differently. > > The following program fragment nicely prints "Smaller or Equal": > > if ((Character'Pos('z') ** Character'Pos('z')) > > (Character'Pos('z') ** Character'Pos('z'))) > then > Put_Line("Larger"); > else > Put_Line("Smaller or Equal"); > end if; > > This is really cool -- the sematic of Universal_Integer enables us to > perform operations over huge integers without overflows. It does not, the range of Universal_Integer at run-time is implementation-dependent. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-09 15:20 ` Stefan.Lucks 2013-04-09 16:15 ` Dmitry A. Kazakov @ 2013-04-09 22:59 ` Randy Brukardt 1 sibling, 0 replies; 242+ messages in thread From: Randy Brukardt @ 2013-04-09 22:59 UTC (permalink / raw) <Stefan.Lucks@uni-weimar.de> wrote in message news:alpine.DEB.2.02.1304091606430.12289@debian... ... > If you insist that all the operations (such as the "**") above are over > Universal_Integer, than that would mean the semantic of Universal_Integer > is allowed to change, depending on compile. versus run time. Unfortunately, that is mandated by Ada. >That would be even more "pseudo". ;-) Darn right. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-09 8:17 ` Dmitry A. Kazakov 2013-04-09 15:20 ` Stefan.Lucks @ 2013-04-09 22:57 ` Randy Brukardt 2013-04-10 7:30 ` Dmitry A. Kazakov 2013-04-10 8:00 ` Root_String'Class? (Was: Is this expected behavior or not) Jacob Sparre Andersen 1 sibling, 2 replies; 242+ messages in thread From: Randy Brukardt @ 2013-04-09 22:57 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:ihi0ajan1ehu.iplgjkwsfpii.dlg@40tude.net... ... > Now consider Ada.Strings.Unbounded. It has a whole lot of mixed string > type > operation declared: Append, "&", "=", "<", ">", ">=", "<=". Yes, a horrible mistake. It prevents Ada.Strings.Unbounded from ever having any literals, because they could never have a unique type. Mixing types = mistake!! Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-09 22:57 ` Randy Brukardt @ 2013-04-10 7:30 ` Dmitry A. Kazakov 2013-04-10 8:00 ` Root_String'Class? (Was: Is this expected behavior or not) Jacob Sparre Andersen 1 sibling, 0 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-10 7:30 UTC (permalink / raw) On Tue, 9 Apr 2013 17:57:55 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:ihi0ajan1ehu.iplgjkwsfpii.dlg@40tude.net... > ... >> Now consider Ada.Strings.Unbounded. It has a whole lot of mixed string >> type operation declared: Append, "&", "=", "<", ">", ">=", "<=". > > Yes, a horrible mistake. It prevents Ada.Strings.Unbounded from ever having > any literals, because they could never have a unique type. Overloading is what leads to problems. There are ways to resolve it. One approach could be literal extension. Usually it is thought that Wide_Character is a constrained Wide_Wide_Character and Character is a constrained Wide_Character: Wide_Wide_Character -> Wide_Character -> Character This cases corresponding values to overlap: 'A' is either Wide_Wide_Character or Wide_Character or Character One could consider an alternative derivation based on enumeration extension: Character -> Wide_Character -> Wide_Wide_Character That would remove overloading of literals. 'A' will be Character only. The reason why this did not work in Ada was due to lack of multi-methods. Ada character/string operations were all overloaded, so in order to make them work with literals, one had to overload literals as well. With multi-methods there will be no need to overload literals anymore: X : Wide_Character := 'A'; -- This is OK with multi-method Resolved to procedure ":=" (Left : in out Wide_Character; Right : Character); -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Root_String'Class? (Was: Is this expected behavior or not) 2013-04-09 22:57 ` Randy Brukardt 2013-04-10 7:30 ` Dmitry A. Kazakov @ 2013-04-10 8:00 ` Jacob Sparre Andersen 2013-04-10 21:48 ` Randy Brukardt 1 sibling, 1 reply; 242+ messages in thread From: Jacob Sparre Andersen @ 2013-04-10 8:00 UTC (permalink / raw) Randy Brukardt wrote: [ many interesting things about string types ] You mention creating an abstract tagged Root_String type and deriving actual string types from it. Do you have some concrete ideas for how you would do it? Could it be done with what we have in Ada 2012? Or would it require some extensions to the language? Greetings, Jacob -- �When Roman engineers built a bridge, they had to stand under it while the first legion marched across. If programmers today worked under similar ground rules, they might well find themselves getting much more interested in Ada!� -- Robert Dewar ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Root_String'Class? (Was: Is this expected behavior or not) 2013-04-10 8:00 ` Root_String'Class? (Was: Is this expected behavior or not) Jacob Sparre Andersen @ 2013-04-10 21:48 ` Randy Brukardt 0 siblings, 0 replies; 242+ messages in thread From: Randy Brukardt @ 2013-04-10 21:48 UTC (permalink / raw) "Jacob Sparre Andersen" <sparre@nbi.dk> wrote in message news:8761zuizmq.fsf_-_@adaheads.sparre-andersen.dk... > Randy Brukardt wrote: > > [ many interesting things about string types ] > > You mention creating an abstract tagged Root_String type and deriving > actual string types from it. Do you have some concrete ideas for how > you would do it? Could it be done with what we have in Ada 2012? Or > would it require some extensions to the language? There is a rough proposal in the body of AI12-0021-1/01. Please note that this is completely my invention which has not be vetted by anyone. The only needed magic is to allow string literals for the root type. Everything else needed is already provided by Ada 2012. (Note that I turned slices into functions, we'd need an extra facility to support the slice syntax. I don't find that important enough to bother with, but perhaps others will disagree.) Most of the less-primitive operations would primarily be supported via Ada.Strings.General (which would be similar in contents to Ada.Strings.Fixed). One imagines that types similar to Unbounded_String and Bounded_Striing would also be provided as members of Root_String'Class, so they would have much smaller packages and would be much more interoperable. The downside is that elements would be accessed as Wide_Wide_Characters, which in some cases (16-bit processors, for instance) would make things more expensive than currently. And of course, a lot more dispatching. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-08 15:35 ` Stefan.Lucks 2013-04-08 19:08 ` Dmitry A. Kazakov @ 2013-04-09 22:53 ` Randy Brukardt 1 sibling, 0 replies; 242+ messages in thread From: Randy Brukardt @ 2013-04-09 22:53 UTC (permalink / raw) <Stefan.Lucks@uni-weimar.de> wrote in message news:alpine.DEB.2.02.1304081709350.8693@debian... On Mon, 8 Apr 2013, Dmitry A. Kazakov wrote: >>> Because even if the implementation of Ada.Text_IO.Open would know the >>> encoding of the filename, it could do nothing useful with it. >> >> ??? It must know the encoding in order to handle the file properly. > >Ah! Finally you seem to understand where the problem is! > >Ada.Text_IO would have to know the encoding, but it doesn't. Of course it does, the encoding is 8-bit Latin-1 (in the absence of any implementation-defined stuff). If you want UCS-16, use Wide_Text_IO. The name of the package chooses the representation. Ada doesn't really support any other encodings than these. > So it just treats the string like a sequence of bytes (much like a > C-string) and > leaves it to the Application Programmer to apply the proper conversion > before. Which means, the conversion must be done explicitly. You can do that, but (a) it's not really true (Text_IO has to know about LF and CR and FF to deal with line endings and the like) - you get lucky with UTF-8 because the representation of those is the same as Latin-1; (b) conversions are expensive. It would be more appropriate to use a stream solution for non-Latin-1 representations, but that of course has it's own problems. Probably the best we can do today (Text_IO is going nowhere) is a combination of Root_String'Class operations (so that the *program* representation is irrelevant) and form parameters to specify file representation. I don't see any real problems with that. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-08 8:59 ` Dmitry A. Kazakov 2013-04-08 15:35 ` Stefan.Lucks @ 2013-04-09 22:45 ` Randy Brukardt 2013-04-10 7:37 ` Dmitry A. Kazakov 1 sibling, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-04-09 22:45 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:imfrovuxjjo6.6ebpr0pq5kgr.dlg@40tude.net... ... >> You cannot define an object O: >> Universal_Integer, neither a function returning Universal_Integer ... > > As if it were relevant. But you are wrong here. Universal types leak into > run time through attributes. I.e. you do have objects of universal types > at > run time in expressions like > > Integer'Pos (X) * 2 A major design flaw of the language, IMHO. Run-time universal operations are nonsense; they have completely different semantics than the compile-time version -- which is dangerous as well as confusing. The run-time version is really just Long_Integer with dangerous implicit conversions. A step backwards. Stefan has it right (even if Ada doesn't): Universal integer is a pseudo-type that only should have an existence to the compiler. Randy. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-09 22:45 ` Randy Brukardt @ 2013-04-10 7:37 ` Dmitry A. Kazakov 2013-04-10 22:15 ` Randy Brukardt 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-10 7:37 UTC (permalink / raw) On Tue, 9 Apr 2013 17:45:24 -0500, Randy Brukardt wrote: > Stefan has it right (even if Ada doesn't): Universal integer is a > pseudo-type that only should have an existence to the compiler. This is what happens when theories face reality. You are ready to declare Ada design wrong in order to save the theory. (:-)) As an exercise compare how much of Ada design is wrong according to your theory vs. mine? -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-10 7:37 ` Dmitry A. Kazakov @ 2013-04-10 22:15 ` Randy Brukardt 2013-04-11 7:33 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-04-10 22:15 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:dqljoxvn36my.xkv88psqukp9$.dlg@40tude.net... > On Tue, 9 Apr 2013 17:45:24 -0500, Randy Brukardt wrote: > >> Stefan has it right (even if Ada doesn't): Universal integer is a >> pseudo-type that only should have an existence to the compiler. > > This is what happens when theories face reality. You are ready to declare > Ada design wrong in order to save the theory. (:-)) Yup. Because it is, and the theory works well. :-) I certainly don't believe Ada is perfect, and some parts of it are screwed up and much more complex than necessary. I'd love to make an Ada-like language that had fewer warts. But blowing up its models and starting over would certainly introduce a new set of warts because of not understanding all of the issues very well. Staying as close as possible to the existing models lets us build on the existing experience (and for Ada itself, is absolutely necessary). > As an exercise compare how much of Ada design is wrong according to your > theory vs. mine? So far as I know, run-time universals and the occassional mixed type operation is it. I'd dump some features of Ada as insufficiently valuable if starting from scratch (visibility in nested units would get a makeover), but the design would be largely the same. You seem to want to completely dump the Ada design in favor of something based on multi-methods. Multi-methods are the same as weak typing to me, I don't want to see them explicitly or implicitly. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-10 22:15 ` Randy Brukardt @ 2013-04-11 7:33 ` Dmitry A. Kazakov 2013-04-11 22:37 ` Randy Brukardt 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-11 7:33 UTC (permalink / raw) On Wed, 10 Apr 2013 17:15:14 -0500, Randy Brukardt wrote: > You seem to want to completely dump the Ada design in favor of something > based on multi-methods. Nope, I want to reaffirm Ada design in more fundamental terms. I don't want to change the semantics which is OK to me. > Multi-methods are the same as weak typing to me, I > don't want to see them explicitly or implicitly. Exactly the opposite. Multi-methods is a strongly typed description of what the language does anyway. The alternative is overloading proven to work extremely poor. The point is that the class [e.g. of string types] is there. You can handle it ad-hoc using overloading [Ada 95 solution, which is called ad-hoc polymorphism] Or you can articulate the class explicitly. You do it in your proposal anyway as Root_String_Type. In that case there is simply no alternative to multi-methods because n-ary operations do not have preferable argument. So what are you going to do with this? You ditch operations, literals, slices. A great theory! -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-11 7:33 ` Dmitry A. Kazakov @ 2013-04-11 22:37 ` Randy Brukardt 2013-04-12 7:47 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-04-11 22:37 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:1q6gm7foi87kr.i2q54bm8sy83.dlg@40tude.net... ... > In that case there is simply no alternative to multi-methods because n-ary > operations do not have preferable argument. So what are you going to do > with this? You ditch operations, literals, slices. A great theory! Yup, operations that you don't need, and that are dangerous on top of that. You continually claim that you need multi-methods without a shred of proof. Changing/comparing different representations is something that a program should do very rarely, if at all. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-11 22:37 ` Randy Brukardt @ 2013-04-12 7:47 ` Dmitry A. Kazakov 2013-04-13 0:26 ` Randy Brukardt 2013-04-13 0:35 ` Randy Brukardt 0 siblings, 2 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-12 7:47 UTC (permalink / raw) On Thu, 11 Apr 2013 17:37:31 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:1q6gm7foi87kr.i2q54bm8sy83.dlg@40tude.net... > ... >> In that case there is simply no alternative to multi-methods because n-ary >> operations do not have preferable argument. So what are you going to do >> with this? You ditch operations, literals, slices. A great theory! > > Yup, operations that you don't need, and that are dangerous on top of that. > You continually claim that you need multi-methods without a shred of proof. The list of operations required for strings was listed many times: function "&" (L, R : Root_String_Type) return Root_String_Type; function "=" (L, R : Root_String_Type) return Boolean; function "/=" (L, R : Root_String_Type) return Boolean; function ">=" (L, R : Root_String_Type) return Boolean; function "<=" (L, R : Root_String_Type) return Boolean; function ">" (L, R : Root_String_Type) return Boolean; function "<" (L, R : Root_String_Type) return Boolean; function Overwrite (Source : in Root_String_Type); Position : in Positive; New_Item : in Root_String_Type) return Root_String_Type); should I continue? It is hundreds of operations, literally. Take into account a huge set of multi-dispatch operation with containers of strings, e.g. Character_Set and Character_Mapping. It is thousands of operations you want to overload? Drop altogether? > Changing/comparing different representations is something that a program > should do very rarely, if at all. Give "a shred of proof" that Wide_Wide_String must have same representation as String. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-12 7:47 ` Dmitry A. Kazakov @ 2013-04-13 0:26 ` Randy Brukardt 2013-04-13 0:35 ` Randy Brukardt 1 sibling, 0 replies; 242+ messages in thread From: Randy Brukardt @ 2013-04-13 0:26 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:6ywdes8pgbd8$.alujya2d4454$.dlg@40tude.net... > On Thu, 11 Apr 2013 17:37:31 -0500, Randy Brukardt wrote: > >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >> news:1q6gm7foi87kr.i2q54bm8sy83.dlg@40tude.net... >> ... >>> In that case there is simply no alternative to multi-methods because >>> n-ary >>> operations do not have preferable argument. So what are you going to do >>> with this? You ditch operations, literals, slices. A great theory! >> >> Yup, operations that you don't need, and that are dangerous on top of >> that. >> You continually claim that you need multi-methods without a shred of >> proof. > > The list of operations required for strings was listed many times: > > function "&" (L, R : Root_String_Type) return Root_String_Type; > function "=" (L, R : Root_String_Type) return Boolean; > function "/=" (L, R : Root_String_Type) return Boolean; > function ">=" (L, R : Root_String_Type) return Boolean; > function "<=" (L, R : Root_String_Type) return Boolean; > function ">" (L, R : Root_String_Type) return Boolean; > function "<" (L, R : Root_String_Type) return Boolean; > function Overwrite (Source : in Root_String_Type); > Position : in Positive; > New_Item : in Root_String_Type) > return Root_String_Type); > > should I continue? It is hundreds of operations, literally. Take into > account a huge set of multi-dispatch operation with containers of strings, > e.g. Character_Set and Character_Mapping. It is thousands of operations > you > want to overload? Drop altogether? > >> Changing/comparing different representations is something that a program >> should do very rarely, if at all. > > Give "a shred of proof" that Wide_Wide_String must have same > representation > as String. > > -- > Regards, > Dmitry A. Kazakov > http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-12 7:47 ` Dmitry A. Kazakov 2013-04-13 0:26 ` Randy Brukardt @ 2013-04-13 0:35 ` Randy Brukardt 2013-04-13 7:07 ` Dmitry A. Kazakov 1 sibling, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-04-13 0:35 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:6ywdes8pgbd8$.alujya2d4454$.dlg@40tude.net... > On Thu, 11 Apr 2013 17:37:31 -0500, Randy Brukardt wrote: > >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >> news:1q6gm7foi87kr.i2q54bm8sy83.dlg@40tude.net... >> ... >>> In that case there is simply no alternative to multi-methods because >>> n-ary >>> operations do not have preferable argument. So what are you going to do >>> with this? You ditch operations, literals, slices. A great theory! >> >> Yup, operations that you don't need, and that are dangerous on top of >> that. >> You continually claim that you need multi-methods without a shred of >> proof. > > The list of operations required for strings was listed many times: > > function "&" (L, R : Root_String_Type) return Root_String_Type; > function "=" (L, R : Root_String_Type) return Boolean; > function "/=" (L, R : Root_String_Type) return Boolean; > function ">=" (L, R : Root_String_Type) return Boolean; > function "<=" (L, R : Root_String_Type) return Boolean; > function ">" (L, R : Root_String_Type) return Boolean; > function "<" (L, R : Root_String_Type) return Boolean; > function Overwrite (Source : in Root_String_Type); > Position : in Positive; > New_Item : in Root_String_Type) > return Root_String_Type); > > should I continue? It is hundreds of operations, literally. Hundreds? You've lost your mind. My rough proposal had 6 (not counting the operators). The vast majority of interesting operations should be class-wide, not primitive. That includes pretty much everything in the Ada.Strings.whatever packages. >Take into > account a huge set of multi-dispatch operation with containers of strings, > e.g. Character_Set and Character_Mapping. It is thousands of operations > you > want to overload? Drop altogether? I don't see this at all. The element type here is Wide_Wide_Character (only), since this is all about Unicode and there's no important reason to shorten the representation of singletons. So there's no multi-dispatch and all of the existing character sets and mappings can be used as they currently are defined. >> Changing/comparing different representations is something that a program >> should do very rarely, if at all. > > Give "a shred of proof" that Wide_Wide_String must have same > representation > as String. It doesn't have the same representation; they should never be used together. Give me any reason (beyond existing broken interfaces, which we would fix) that you should be mixing these two types. Either you're an "ugly American" (like me) that thinks Internationalization is mainly about keeping up the barriers between people - everyone should use English and forget everything else! For us, we'll just use String and we're already happy. For everyone else, they'll have to use Wide_Wide_String (or some new string type) everywhere. Converting to 8-bit just loses information, and that's a bug in many supposely internationalized programs. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-13 0:35 ` Randy Brukardt @ 2013-04-13 7:07 ` Dmitry A. Kazakov 0 siblings, 0 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-13 7:07 UTC (permalink / raw) On Fri, 12 Apr 2013 19:35:07 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:6ywdes8pgbd8$.alujya2d4454$.dlg@40tude.net... >> On Thu, 11 Apr 2013 17:37:31 -0500, Randy Brukardt wrote: >> >>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >>> news:1q6gm7foi87kr.i2q54bm8sy83.dlg@40tude.net... >>> ... >>>> In that case there is simply no alternative to multi-methods because n-ary >>>> operations do not have preferable argument. So what are you going to do >>>> with this? You ditch operations, literals, slices. A great theory! >>> >>> Yup, operations that you don't need, and that are dangerous on top of that. >>> You continually claim that you need multi-methods without a shred of proof. >> >> The list of operations required for strings was listed many times: >> >> function "&" (L, R : Root_String_Type) return Root_String_Type; >> function "=" (L, R : Root_String_Type) return Boolean; >> function "/=" (L, R : Root_String_Type) return Boolean; >> function ">=" (L, R : Root_String_Type) return Boolean; >> function "<=" (L, R : Root_String_Type) return Boolean; >> function ">" (L, R : Root_String_Type) return Boolean; >> function "<" (L, R : Root_String_Type) return Boolean; >> function Overwrite (Source : in Root_String_Type); >> Position : in Positive; >> New_Item : in Root_String_Type) >> return Root_String_Type); >> >> should I continue? It is hundreds of operations, literally. > > Hundreds? You've lost your mind. My rough proposal had 6 (not counting the > operators). The vast majority of interesting operations should be > class-wide, not primitive. That includes pretty much everything in the > Ada.Strings.whatever packages. Ada 95 already has Wide_Wide_String packages. For fans of explicit conversions everything is there. Why bothering with new hierarchies? [And repeating old mistakes?] >>Take into >> account a huge set of multi-dispatch operation with containers of strings, >> e.g. Character_Set and Character_Mapping. It is thousands of operations >> you want to overload? Drop altogether? > > I don't see this at all. The element type here is Wide_Wide_Character > (only), since this is all about Unicode and there's no important reason to > shorten the representation of singletons. So there's no multi-dispatch and > all of the existing character sets and mappings can be used as they > currently are defined. Translating String using a Wide_Wide mapping is a mixed operation! >>> Changing/comparing different representations is something that a program >>> should do very rarely, if at all. >> >> Give "a shred of proof" that Wide_Wide_String must have same >> representation as String. > > It doesn't have the same representation; they should never be used together. > Give me any reason (beyond existing broken interfaces, which we would fix) > that you should be mixing these two types. The reason is that Wide_Wide_String and String represent exactly same thing. The motivation to have String is exclusively optimization. Same applies to Unbounded_String and to encodings. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-05 16:29 ` Dmitry A. Kazakov 2013-04-05 19:55 ` Stefan.Lucks @ 2013-04-06 1:38 ` Randy Brukardt 1 sibling, 0 replies; 242+ messages in thread From: Randy Brukardt @ 2013-04-06 1:38 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:pgrgoxdhtshv$.z253qtbqarkc.dlg@40tude.net... > On Fri, 5 Apr 2013 17:16:59 +0200, Stefan.Lucks@uni-weimar.de wrote: ... > I disagree. They wanted to prevent the mess of PL/1 where *arbitrary* > conversions were applied to semantically unrelated types. Types like > Character and Wide_Character are semantically related. Conversion from one > to another is perfectly well defined. All numeric types are semantically related. All array types are semantically related. But that doesn't mean that implicit conversions are a good idea even if they are well-defined. Every type that has a different representation has different semantics, and those differences are important in enough cases that implicit conversion between different representations is banned. This *is* an accurate description of Ada's design: you can't derive a numeric type that has primitive operations if you try to change its representation, and that's because the implicit conversions of inheritance were not to be allowed if the representation is different. (This is one of the things that makes Ada 83 derivation so utterly useless.) > Furthermore what Randy proposes will actually be worse than pitiful > Unbounded_String. For them you could at least do this: > > type Relative_File_Path is new Unbounded_String; > type Absolute_File_Path is new Unbounded_String; > > You could not do that for tagged strings. Right. You'd have to write: type Relative_File_Path is new Unbounded_String is null record; type Absolute_File_Path is new Unbounded_String is null record; Horrifyingly more complex. ;-) Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-05 9:57 ` Dmitry A. Kazakov 2013-04-05 12:45 ` Stefan.Lucks @ 2013-04-06 1:20 ` Randy Brukardt 2013-04-06 5:20 ` Usefulness of OOP (was Is this expected behavior or not) J-P. Rosen 2013-04-07 7:00 ` Is this expected behavior or not Dmitry A. Kazakov 1 sibling, 2 replies; 242+ messages in thread From: Randy Brukardt @ 2013-04-06 1:20 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:1bj564vat3q1j$.1s4d00rlzx4ux$.dlg@40tude.net... > On Thu, 4 Apr 2013 15:31:23 -0500, Randy Brukardt wrote: > >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >> news:1fmcdkj58brky.bjedt0pr39cd$.dlg@40tude.net... >>> On Wed, 3 Apr 2013 19:04:24 -0500, Randy Brukardt wrote: >>> >>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> 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? >> >> The same way it is an error to compare a float and an integer. > > It is not same. R and Z are different mathematical constructs. Unicode > strings, all of them, are semantically exactly same except for encoding > [representation] and constraints put on the code point set. We're not talking about "Unicode strings", whatever that is. We're talking about an abstract string type, with different sets of characters, not necessarily overlapping. Automatically converting Wide_String into String is unsafe as it loses information, and that's even more true once you start thinking about other character sets. I'm sure that there are cases where you can get away with automatic conversions, but you don't need that and you certainly can't do it all the time. So why support it at all? >> You could >> make a rule with somewhat sensible results, but it's a bad idea because >> it >> hides more errors than it simplifies correct code. > > If that were so, you should not have them in the same hierarchy. You want > to have one class in order to share operations like Put_Line. These > operations are far more questionable than comparison. If you challenge > comparison, you should not do Put_Line either. To some extent, you are right. If you can't convert the value into some universal representation, then you can't implement class-wide operations, either. And that suggests that the entire idea is bad. Indeed, that indicates that all OOP is bad because it destroys type-checking. Perhaps I should forget that I ever heard of it?? But in any case, there are two important differences here: single operand operations vs. multiiple operand operations, and the declaration (by using 'Class) that you are explicitly not caring about type. Perhaps it is orthodoxy, but I don't believe that you should ever mix types without explicit conversions, meaning that only single operand operations can have 'Class operands. (I can't think off hand of any cases where we ever had more than one operand of a class in a Claw operation, but I may have forgotten something.) > You design decisions are motivated by compiler implementation issues not > by > the actual properties of strings. If you can't implement it, no mattter how wonderful some idea may be, it's still irrelevant. ... > Now this: > > function Get_Text (Control : Edit_Box) return Root_String_Type; First, this is illegal because Root_String_Type is abstract, and you can't have a function returning an abstract type. Second, you can't implement that in Claw (or Ada), because the Edit_Box is an "in" parameter and you need to modify some of its components in order to deal with the state changes of the edit box. So you have have to have something like: function Get_Text (Control : in out Edit_Box) return Root_String_Type'Class; But this is very different than the procedure form. In the procedure case, the object passed in determines the type and representation of the result. In the function case, the function returns whatever type it feels like, and just about the only thing you can do with it is assign it to an object or pass it to a class-wide parameter. So this is trivial to implement: return any old new object that you like. Probably here again you want to totally redesign Ada, but that isn't very likely. >>>>> 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. >> >> Which is 95% of the cases that you would want. > > No more than 20-30% actually. OK, it's 95% of the cases that occur in actual practice, with the possible exception with people that overuse OOP constructs and make their systems more complex than needed. :-) ... >> Mixed operations are almost always a non-starter for any type. > > Mixed operations are a must for all algebraic types and all string types. > Ada 83 had it mixed from the start, e.g. Universal_Integer vs. Integer. > Ada > 95 added mixed operations for access types. Actually, those aren't really mixed, as Universal has the same relationship to other types as 'Class does. In some ways, these act as separate types, but given the automatic conversions they really aren't that - they're a set of types that includes the associated specific types. ... >> the Ada 95 effects make it absolutely >> necessary to avoid functions returning a controlled type, else creating >> extensions is so hard that no one will do it. > > I don't know where you get that idea. I never had any problem with > abstract > factories. Well, I have. As I previously explained, the abstract routines and functions in the Claw Builder root types make it so time-consuming to create an extension (the last one I did took around 20 hours to write, and even then I never finished it) that it's impractical to do so. If you have only one such routine, there is no significant problem, but you have to greatly limit the number or extensions are impractical. The only practical extensions inherit virtually all of their implementation (at least initially) from their parent. [This is how Claw itself works, it's a lot easy to deal with than the builder is.] It's a major reason why I don't believe in interfaces, as the effort to create implementations for every included operation is just too much of a "Big Bang" for my programming style. (If I can't have something compilable and testable in a few hours, I get very uncomfortable, because that is the only way to detect gross mistakes -- otherwise, one can waste days building something that doesn't work.) > Actual problem is fighting senseless limitations imposed by the > language, which makes design very hard as you never know if the derived > type would be possible to construct. Limited aggregates/functions, broken > initialization/finalization, leaking separation of specification and > implementation, missing initialization/finalization of class-wides etc. > That makes it difficult. Not sure why most of those things would cause any real issues, as most of them give more, not less, capability. But it isn't worth discussing that. >>> 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.] >> >> It doesn't work for portability reasons for some compilers to call Adjust >> during the evaluation of parameters and other compilers to not call >> Adjust. > > When the type neither specified as either by-reference nor as by-value, it > shall be exactly this way. I don't understand why this is relevant. > >> It would make performance wildly variable and possibly cause bugs (if the >> program unintentionally depended on one or the other. > > Yes, the language permits compilers implemented poorly, and? This has nothing to do with compilers. It has to do with *poorly designed programs*. It's certainly true that a program that depends on by-copy or by-reference passing is wrong; the compiler should be free to choose. But this is an undetectable error. And bringing Adjust into it makes it much worse, because it's easy to write code that doesn't work if Adjust is called (you probably can get infinite recursion that way). That sort of thing can't be implementation-defined. ... >>>> 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. Here you are saying that you can't redispatch because you insist on a model that doesn't allow it. I don't think that is a very good case. :-) You have to justify eliminating re-dispatch, then, and only then, can you chose a model that doesn't allow it. >>>> 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. >> >> Objects of limited types are always assumed to have an identity; > > No. E.g. task and protected types lack type identity. Only tagged types > have type identity. > > Note that type identity /= object identity (e.g. machine address where the > object resides). I don't think that they ought to be separated. If you have object identity, and every object has a nominal type, it does not make sense to lose that information. There are no values of a limited type, only objects. I see your point for non-limited values, as the type of a value is not necessarily determined. But that's not true for objects. Here again, you are justifying your model by simply eliminating a property that all objects have and saying that I can't fit that into my model so I won't. >>>> 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. >> >> That's already true, you just don't have inheritance of operations for >> these >> hierarchies. So exactly what you are simplifying but introducing this >> whole >> new notion of type cloning, this new notion of when you must override >> routines, and so on?? > > I don't introduce anything Ada 83 or 95 do not have already. I want to > lift > meaningless language limitations which lead to silly design decisions like > inability to concatenate or compare two strings. That's a feature, not a bug. :-) And it's one I would be extremely surprised to see changed in Ada (or any other strongly typed language, for that matter). >>> You want to derive each string type straight from Root_String. >> >> Yes, or from related ones. There is no significant value to doing >> anything >> else - as you point out, if you can inherit the operations, the >> representations have to be compatible. So there is nothing useful you can >> do >> with multiple levels. > > Encoding! You have to reimplement *every* operation for a new representation (in your model as well as in existing Ada). So you are gaining absolutely nothing over using interfaces for any added operations. You need to have a more complete example than that if you want to convince me of anything. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Usefulness of OOP (was Is this expected behavior or not) 2013-04-06 1:20 ` Randy Brukardt @ 2013-04-06 5:20 ` J-P. Rosen 2013-04-06 10:31 ` Dmitry A. Kazakov 2013-04-07 7:00 ` Is this expected behavior or not Dmitry A. Kazakov 1 sibling, 1 reply; 242+ messages in thread From: J-P. Rosen @ 2013-04-06 5:20 UTC (permalink / raw) Le 06/04/2013 03:20, Randy Brukardt a écrit : > And that suggests that the entire idea is bad. Indeed, that indicates that > all OOP is bad because it destroys type-checking. Perhaps I should forget > that I ever heard of it?? Can't resist jumping on this one... Yes, OOP increases dynamicity, which is good in some contexts, at the cost of decreasing strong typing and static checkability. Drawbacks and benefits, you have to decide depending on context. Nothing new with that... Just mentionned it to counter those who claim that OOP is the universal cure, and that other methods (like good ol' structured programming) are just remainings of the past. -- J-P. Rosen Adalog 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00 http://www.adalog.fr ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Usefulness of OOP (was Is this expected behavior or not) 2013-04-06 5:20 ` Usefulness of OOP (was Is this expected behavior or not) J-P. Rosen @ 2013-04-06 10:31 ` Dmitry A. Kazakov 2013-04-06 18:43 ` Georg Bauhaus 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-06 10:31 UTC (permalink / raw) On Sat, 06 Apr 2013 07:20:39 +0200, J-P. Rosen wrote: > Just mentionned it to counter those who claim that OOP > is the universal cure, and that other methods (like good ol' structured > programming) are just remainings of the past. Actually both OOA/D and structured programming remain deep in the past as they share the same principle of designing rather an individual system, which leads to extremely fragile design. Traditional OOA/D considers the system composed out of objects collaborating with each other. This is quite similar to modules of structured approach. The difference is in object orientation against more loose [almost ad-hoc] procedural decomposition of classic structured programming. Both greatly hinder re-use and fail to adapt to the reality of ever changing requirements. [*] What is good in OO is more advanced ADT, which supports decomposition in more general, and thus more stable, terms, e.g. along types and sets of types (AKA generic programming). It in turn requires more advanced system of modules to hold ADTs, e.g. Ada's system of packages. Comparing to decomposition along types and sets of types, traditional OOA/D and structured programming decompose software along individual objects/values/routines. Paleolith. P.S. I don't consider type safety issue because structured programming did not operate types. It was basically pre-typed = untyped. ---------------------------- * There is a whole "OO religion" teaching that the world indeed consists out of objects which program design could capture. This in turn would ensure stability of the design. Utter nonsense, for sure. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Usefulness of OOP (was Is this expected behavior or not) 2013-04-06 10:31 ` Dmitry A. Kazakov @ 2013-04-06 18:43 ` Georg Bauhaus 0 siblings, 0 replies; 242+ messages in thread From: Georg Bauhaus @ 2013-04-06 18:43 UTC (permalink / raw) On 06.04.13 12:31, Dmitry A. Kazakov wrote: > Both [procedural decomposition and OO] greatly hinder re-use and > fail to adapt to the reality of ever changing requirements. Requirements do change. Change is always managed in some way. What if we knew well how methods and languages influence the cost and outcome of change management? I mean formally, more scientifically. We do know about time spent on adapting software to changing requirements. This means we know the cost. But do we know why this or that change has cost more or less? I mean, formally, so that some theory could lead the way to better methods, and to better languages. A science of successful reactions to change, in terms of methods of programming, would seem to be a bigger project for academics co-operating with industry. Is it on anyone's radar? I speculate that proprietary building blocks for software are moving ahead, without feedback arriving in language design. (I hope I am wrong.) A possible idea that I admit is foggy: Is there something in GoF patterns worth of making them new primitives of formal expression? ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-06 1:20 ` Randy Brukardt 2013-04-06 5:20 ` Usefulness of OOP (was Is this expected behavior or not) J-P. Rosen @ 2013-04-07 7:00 ` Dmitry A. Kazakov 2013-04-09 23:24 ` Randy Brukardt 1 sibling, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-07 7:00 UTC (permalink / raw) On Fri, 5 Apr 2013 20:20:58 -0500, Randy Brukardt wrote: > Automatically converting Wide_String into String is > unsafe as it loses information, and that's even more true once you start > thinking about other character sets. All existing character sets are subsets of Unicode. String could be an Ada subtype of Wide_String. Only difference is in the representation. Even more this applies to encoding. Clearly encoding has nothing to do with the content of a string. > And that suggests that the entire idea is bad. Indeed, that indicates that > all OOP is bad because it destroys type-checking. Perhaps I should forget > that I ever heard of it?? You conflate type checking with representation checking. There is no need to check how a string is represented. > But in any case, there are two important differences here: single operand > operations vs. multiiple operand operations, This difference is only important because the type model you deploy cannot handle the later. There should be something wrong with the model then. >> Now this: >> >> function Get_Text (Control : Edit_Box) return Root_String_Type; > > First, this is illegal because Root_String_Type is abstract, and you can't > have a function returning an abstract type. > > Second, you can't implement that in Claw (or Ada), because the Edit_Box is > an "in" parameter and you need to modify some of its components in order to > deal with the state changes of the edit box. > > So you have have to have something like: > > function Get_Text (Control : in out Edit_Box) return > Root_String_Type'Class; You will need explicit conversions wherever you use Get_Text: X : UTF8_String := Box.Get_Text; or Open (Box.Get_Text); >>>>>> 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. >>> >>> Which is 95% of the cases that you would want. >> >> No more than 20-30% actually. > > OK, it's 95% of the cases that occur in actual practice, They don't occur in practice because the language simply does not support it. As for cascaded dispatch, it is incredibly error prone. Note that cascaded dispatch involves complementary operations, e.g. let you dispatch on T1<T2: function "<" (Left : T; Right : T'Class) return Boolean; If T2 is a descendant of T1, you have to re-dispatch on T2 within the body of "<". But that would invert the order of arguments! This is another operation (complementary) you must go after: not (T2 >= T1) Yet another issue is preventing recursion of cascaded dispatch. You need a whole set of internal operations with additional parameters to keep track of re-dispatching calls. It is exceptionally difficult to implement already in such simple case as <. >>> the Ada 95 effects make it absolutely >>> necessary to avoid functions returning a controlled type, else creating >>> extensions is so hard that no one will do it. >> >> I don't know where you get that idea. I never had any problem with >> abstract factories. > > Well, I have. As I previously explained, the abstract routines and functions > in the Claw Builder root types make it so time-consuming to create an > extension (the last one I did took around 20 hours to write, and even then I > never finished it) that it's impractical to do so. > > If you have only one such routine, Why there should be many? Anyway, if you know how to create such function, you make it class-wide. If you don't know, nobody knows. It must be overridden and the compiler tells you so. There is simply no problem with that. >>>> 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.] >>> >>> It doesn't work for portability reasons for some compilers to call Adjust >>> during the evaluation of parameters and other compilers to not call >>> Adjust. >> >> When the type neither specified as either by-reference nor as by-value, it >> shall be exactly this way. I don't understand why this is relevant. >> >>> It would make performance wildly variable and possibly cause bugs (if the >>> program unintentionally depended on one or the other. >> >> Yes, the language permits compilers implemented poorly, and? > > This has nothing to do with compilers. It has to do with *poorly designed > programs*. It's certainly true that a program that depends on by-copy or > by-reference passing is wrong; the compiler should be free to choose. But > this is an undetectable error. And bringing Adjust into it makes it much > worse, because it's easy to write code that doesn't work if Adjust is called > (you probably can get infinite recursion that way). Are you saying the copy constructors (Adjust) are broken in Ada? They are to me too. Fix them. >>>>> 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. > > Here you are saying that you can't redispatch because you insist on a model > that doesn't allow it. No model exist which would allow re-dispatch on scalar value. Like no model exist where 2+2=5. >>>>> 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. >>> >>> Objects of limited types are always assumed to have an identity; >> >> No. E.g. task and protected types lack type identity. Only tagged types >> have type identity. >> >> Note that type identity /= object identity (e.g. machine address where the >> object resides). > > I don't think that they ought to be separated. If you have object identity, > and every object has a nominal type, it does not make sense to lose that > information. Nothing is lost. You forgot that the parameter was passed by copy, as required by the type, which was by-copy. It is another object in there. Its identity is obviously not the identity of the origin. How could it be otherwise? >>>> You want to derive each string type straight from Root_String. >>> >>> Yes, or from related ones. There is no significant value to doing anything >>> else - as you point out, if you can inherit the operations, the >>> representations have to be compatible. So there is nothing useful you can >>> do with multiple levels. >> >> Encoding! > > You have to reimplement *every* operation for a new representation (in your > model as well as in existing Ada). Most bodies will be inherited per composition with conversion. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-07 7:00 ` Is this expected behavior or not Dmitry A. Kazakov @ 2013-04-09 23:24 ` Randy Brukardt 2013-04-10 8:20 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-04-09 23:24 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:igo6blwn0oas$.wifvpq91hm9m.dlg@40tude.net... > On Fri, 5 Apr 2013 20:20:58 -0500, Randy Brukardt wrote: ... > You conflate type checking with representation checking. There is no need > to check how a string is represented. That's because they're intimately linked. You can't do an operation without knowing how the type is represented. And you should never mix types. Since you seem to think that mixing types is a good thing, you need to find a language where that's possible. Ada is never going to be that language. ... > You will need explicit conversions wherever you use Get_Text: > > X : UTF8_String := Box.Get_Text; > > or > > Open (Box.Get_Text); You wouldn't have to in either of these cases (presuming that Open has a specific type). But of course you could get a type mismatch that way (it would be better when the tag is passed up, as accessibility is). But in general it's a good thing to specify your types, and you do that with explicit conversions. ... >> Well, I have. As I previously explained, the abstract routines and >> functions >> in the Claw Builder root types make it so time-consuming to create an >> extension (the last one I did took around 20 hours to write, and even >> then I >> never finished it) that it's impractical to do so. >> >> If you have only one such routine, > > Why there should be many? If you've got operations like "+" or "*", you'll have a lot of functions returning objects of the type. That's a bad idea for the reasons I mentioned. > Anyway, if you know how to create such function, you make it class-wide. > If > you don't know, nobody knows. It must be overridden and the compiler tells > you so. There is simply no problem with that. Of course there is a problem with that -- if it takes more than a couple of hours to create those functions, you cannot write an extension in a working day (and anything else is too long). I agree that there's probably going to have to be one constructor function, but that's about all that can be tolerated. And, similarly, abstract routines can be tolerated only in very small doses -- no giant interfaces being inherited. .... >>> Yes, the language permits compilers implemented poorly, and? >> >> This has nothing to do with compilers. It has to do with *poorly designed >> programs*. It's certainly true that a program that depends on by-copy or >> by-reference passing is wrong; the compiler should be free to choose. But >> this is an undetectable error. And bringing Adjust into it makes it much >> worse, because it's easy to write code that doesn't work if Adjust is >> called >> (you probably can get infinite recursion that way). > > Are you saying the copy constructors (Adjust) are broken in Ada? They are > to me too. Fix them. Not at all (at least for this topic). The act of calling a routine (*any routine*) usually has detectable side-effects. That's certainly true for Adjust. (It might be bad practice to depend on those side-effects, but language standards cannot legislate program morality.) It cannot be the case that moving a program to a different compiler breaks a *correct* program simply because the new compiler now calls (or does not call) Adjust. We call this "performance incompability"; we can't change the language in such a way that the performance of existing programs is going to change a lot -- doing so has a serious potential for breakage (for instance, it might cause or expose a race condition). >>>>>> 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. >> >> Here you are saying that you can't redispatch because you insist on a >> model >> that doesn't allow it. > > No model exist which would allow re-dispatch on scalar value. Like no > model > exist where 2+2=5. Gee, you can easily redefine "+" in Ada so that 2 + 2 = 5 -- indeed, I believe that one of the ACATS tests does exactly that. Sure seems like the Ada model includes that! I have an tagged universal numeric type implementation, and it certainly allows redispatch. It's not much of a leap to think of it as a scalar type. >>>>>> 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. >>>> >>>> Objects of limited types are always assumed to have an identity; >>> >>> No. E.g. task and protected types lack type identity. Only tagged types >>> have type identity. >>> >>> Note that type identity /= object identity (e.g. machine address where >>> the >>> object resides). >> >> I don't think that they ought to be separated. If you have object >> identity, >> and every object has a nominal type, it does not make sense to lose that >> information. > > Nothing is lost. You forgot that the parameter was passed by copy, as > required by the type, which was by-copy. It is another object in there. > Its > identity is obviously not the identity of the origin. How could it be > otherwise? You can't pass types with object identity by-copy. (These are "immutably limited".) So the issue does not come up. Next question?? >>>>> You want to derive each string type straight from Root_String. >>>> >>>> Yes, or from related ones. There is no significant value to doing >>>> anything >>>> else - as you point out, if you can inherit the operations, the >>>> representations have to be compatible. So there is nothing useful you >>>> can >>>> do with multiple levels. >>> >>> Encoding! >> >> You have to reimplement *every* operation for a new representation (in >> your >> model as well as in existing Ada). > > Most bodies will be inherited per composition with conversion. I forget that you seem to think that compilers will magically be able to implement this stuff as if you wrote it by hand. That isn't very likely to happen. The only way to define these conversions would be through a Wide_Wide_String intermediate - the net effect is that the conversions will be quite expensive and you would never, ever want to use such implementations. (Certainly not for any commonly used operations, and the others ought to be class-wide anyway, stuff like Find_Token) You're going to write all-new implementations for each representation, there won't be anything worth inheriting. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-09 23:24 ` Randy Brukardt @ 2013-04-10 8:20 ` Dmitry A. Kazakov 2013-04-10 22:07 ` Randy Brukardt 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-10 8:20 UTC (permalink / raw) On Tue, 9 Apr 2013 18:24:29 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:igo6blwn0oas$.wifvpq91hm9m.dlg@40tude.net... >> On Fri, 5 Apr 2013 20:20:58 -0500, Randy Brukardt wrote: > ... >> You conflate type checking with representation checking. There is no need >> to check how a string is represented. > > That's because they're intimately linked. You can't do an operation without > knowing how the type is represented. That does not explain why representation needs to be checked. Especially for the types like Boolean and Integer. >>> Well, I have. As I previously explained, the abstract routines and functions >>> in the Claw Builder root types make it so time-consuming to create an >>> extension (the last one I did took around 20 hours to write, and even >>> then I never finished it) that it's impractical to do so. >>> >>> If you have only one such routine, >> >> Why there should be many? > > If you've got operations like "+" or "*", you'll have a lot of functions > returning objects of the type. That's a bad idea for the reasons I > mentioned. You have + and * of GUI objects? That is weird. Anyway if you have arithmetic upon a hierarchy how the compiler is supposed to deduce implementations for derived types? >>>> Yes, the language permits compilers implemented poorly, and? >>> >>> This has nothing to do with compilers. It has to do with *poorly designed >>> programs*. It's certainly true that a program that depends on by-copy or >>> by-reference passing is wrong; the compiler should be free to choose. But >>> this is an undetectable error. And bringing Adjust into it makes it much >>> worse, because it's easy to write code that doesn't work if Adjust is >>> called (you probably can get infinite recursion that way). >> >> Are you saying the copy constructors (Adjust) are broken in Ada? They are >> to me too. Fix them. > > Not at all (at least for this topic). The act of calling a routine (*any > routine*) usually has detectable side-effects. That's certainly true for > Adjust. (It might be bad practice to depend on those side-effects, but > language standards cannot legislate program morality.) You don't make language design dependent and promoting bad practices. >>>>>>> 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. >>> >>> Here you are saying that you can't redispatch because you insist on a >>> model that doesn't allow it. >> >> No model exist which would allow re-dispatch on scalar value. Like no >> model exist where 2+2=5. > > Gee, you can easily redefine "+" in Ada so that 2 + 2 = 5 -- indeed, Then don't expect arithmetic to work. There is a price for each wrong decision. > I have an tagged universal numeric type implementation, and it certainly > allows redispatch. It's not much of a leap to think of it as a scalar type. It is a huge leap, it is from semantically right to wrong. Scalar objects do not have identity, which is a fundamental properly of. Pretty much is based on lack of identity, these properties allow vital program analysis, transformations, e.g. optimization etc. The major flaw of OOPL is an attempt to hand identity on all types. This is simply impossible to do. This is why all of them, including Ada, have types which are more types then others. >>>>>>> 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. >>>>> >>>>> Objects of limited types are always assumed to have an identity; >>>> >>>> No. E.g. task and protected types lack type identity. Only tagged types >>>> have type identity. >>>> >>>> Note that type identity /= object identity (e.g. machine address where >>>> the object resides). >>> >>> I don't think that they ought to be separated. If you have object identity, >>> and every object has a nominal type, it does not make sense to lose that >>> information. >> >> Nothing is lost. You forgot that the parameter was passed by copy, as >> required by the type, which was by-copy. It is another object in there. >> Its identity is obviously not the identity of the origin. How could it be >> otherwise? > > You can't pass types with object identity by-copy. And untagged by-copy types will have none, per design. >>>>>> You want to derive each string type straight from Root_String. >>>>> >>>>> Yes, or from related ones. There is no significant value to doing anything >>>>> else - as you point out, if you can inherit the operations, the >>>>> representations have to be compatible. So there is nothing useful you >>>>> can do with multiple levels. >>>> >>>> Encoding! >>> >>> You have to reimplement *every* operation for a new representation (in >>> your model as well as in existing Ada). >> >> Most bodies will be inherited per composition with conversion. > > I forget that you seem to think that compilers will magically be able to > implement this stuff as if you wrote it by hand. Not at all. The conversion will be provided by the programmer. If he did not define one, he will be required to override things manually. > That isn't very likely to > happen. The only way to define these conversions would be through a > Wide_Wide_String intermediate - the net effect is that the conversions will > be quite expensive and you would never, ever want to use such > implementations. This is exactly the overhead of doing this using the infamous unary plus operation. I don't understand the point you are trying to make. You don't want to override for custom types, you don't want automatic conversion as too expensive. There is no third way. You want to apply explicit conversions at all call points? This is exactly the solution you declared inefficient. It not only inefficient, it is extremely error prone and a major overhead for those unfortunate who have to use the package defined in such manner. The compiler rejects a program. What you do? Erratically place unary pluses before all arguments? But that is invisible. Actually some hundred of them are already visible. For each of them the compiler spits some garbage error messages on you. But the right one you need is not visible. Were was it declared? Was it declared anywhere? Have fun! -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-10 8:20 ` Dmitry A. Kazakov @ 2013-04-10 22:07 ` Randy Brukardt 2013-04-11 7:59 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-04-10 22:07 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:8bj2k30k7i19.w7ehsldwbf7x.dlg@40tude.net... > On Tue, 9 Apr 2013 18:24:29 -0500, Randy Brukardt wrote: ... >>> Why there should be many? >> >> If you've got operations like "+" or "*", you'll have a lot of functions >> returning objects of the type. That's a bad idea for the reasons I >> mentioned. > > You have + and * of GUI objects? That is weird. Anyway if you have > arithmetic upon a hierarchy how the compiler is supposed to deduce > implementations for derived types? Tagged types and extension is used for more than just GUIs. The compiler shouldn't have trouble with inheriting implementations -- we don't do or want multi-methods, after all. Ada only supports that for null extensions; it's easy to extend that so long as an information-preserving conversion is possible. (That would have to be declared by an aspect, I think.) ... >>>>> Yes, the language permits compilers implemented poorly, and? >>>> >>>> This has nothing to do with compilers. It has to do with *poorly >>>> designed >>>> programs*. It's certainly true that a program that depends on by-copy >>>> or >>>> by-reference passing is wrong; the compiler should be free to choose. >>>> But >>>> this is an undetectable error. And bringing Adjust into it makes it >>>> much >>>> worse, because it's easy to write code that doesn't work if Adjust is >>>> called (you probably can get infinite recursion that way). >>> >>> Are you saying the copy constructors (Adjust) are broken in Ada? They >>> are >>> to me too. Fix them. >> >> Not at all (at least for this topic). The act of calling a routine (*any >> routine*) usually has detectable side-effects. That's certainly true for >> Adjust. (It might be bad practice to depend on those side-effects, but >> language standards cannot legislate program morality.) > > You don't make language design dependent and promoting bad practices. If you are starting with a blank page, you're right. If you are building on 30+ years of practice, even "bad practice" has to be taken into account. This is one of the reasons that the language you're suggesting really has to be different than Ada. Ada has too many existing nasties that have to be preserved in order to make the overhaul you're suggesting. We'd be afraid to do it even if it appears to be neutral, just because it would be too risky to make the change. I'd like to make objects [and exceptions] overloadable (it would fix a large percentage of the problems with use clauses and visibility, and unify objects, enumeration literals, and functions - which you should be able to switch between without breaking anything). But the idea is deemed too risky; there is a very low possibility of silent changes in meaning of programs (usually, an illegal program would become legal -- not a problem, or a legal program would become illegal -- a problem, but not showstopping, especially as it would be rare). So the idea is unlikely to go anywhere. And that is a *much* simpler change than what you're suggesting. ... ... >> That isn't very likely to >> happen. The only way to define these conversions would be through a >> Wide_Wide_String intermediate - the net effect is that the conversions >> will >> be quite expensive and you would never, ever want to use such >> implementations. > > This is exactly the overhead of doing this using the infamous unary plus > operation. I don't understand the point you are trying to make. You don't > want to override for custom types, you don't want automatic conversion as > too expensive. There is no third way. You want to apply explicit > conversions at all call points? This is exactly the solution you declared > inefficient. It not only inefficient, it is extremely error prone and a > major overhead for those unfortunate who have to use the package defined > in > such manner. The compiler rejects a program. What you do? Erratically > place > unary pluses before all arguments? But that is invisible. Actually some > hundred of them are already visible. For each of them the compiler spits > some garbage error messages on you. But the right one you need is not > visible. Were was it declared? Was it declared anywhere? Have fun! You're confusing expensive *implicit* operations with expensive explicit ones. I don't care that an explicit type conversion is expensive -- you wrote it, you meant it, and you can see the consequences -- it's right there in the source code. You're right that you could use unary plus for this purpose -- a lot of people do -- but it's also considered an ugly hack. I would never use it to cover up expensive conversions -- I *want* those hard to write, so I only write them where absolutely necessary. And the use of "+" fills your program with ambiguity. OTOH, writing explicit conversions (or function calls with real names) does not have this problem. For instance, I tend to write out the entire name of the conversion between string and unbounded string: Ada.Text_IO.Put_Line (Ada.Strings.Unbounded.To_String (My_Object)); I've used the "+" trick here, but almost exclusively for literals (which should have been part of the type from the beginning). Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-10 22:07 ` Randy Brukardt @ 2013-04-11 7:59 ` Dmitry A. Kazakov 2013-04-11 11:10 ` Georg Bauhaus ` (2 more replies) 0 siblings, 3 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-11 7:59 UTC (permalink / raw) On Wed, 10 Apr 2013 17:07:57 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:8bj2k30k7i19.w7ehsldwbf7x.dlg@40tude.net... >> On Tue, 9 Apr 2013 18:24:29 -0500, Randy Brukardt wrote: > ... >>>> Why there should be many? >>> >>> If you've got operations like "+" or "*", you'll have a lot of functions >>> returning objects of the type. That's a bad idea for the reasons I >>> mentioned. >> >> You have + and * of GUI objects? That is weird. Anyway if you have >> arithmetic upon a hierarchy how the compiler is supposed to deduce >> implementations for derived types? > > Tagged types and extension is used for more than just GUIs. Tagged types are useless when arithmetic operations get involved. It does not work with present design, because type hierarchies are not handled for such operations. > The compiler shouldn't have trouble with inheriting implementations type Real is tagged record Value : Float; end record; function "+" (L, R : Real) return Real; type Complex is new Real with record Img : Float; end record; How is the compiler supposed to inherit "+"? >> You don't make language design dependent and promoting bad practices. > > If you are starting with a blank page, you're right. If you are building on > 30+ years of practice, even "bad practice" has to be taken into account. Nonsense. Bad practice is bad. Longer it lasts bigger is the damage. > This is one of the reasons that the language you're suggesting really has to > be different than Ada. We already discussed that. I want to preserve Ada semantics. It is you who wants completely change the way string types are used in Ada. >>> That isn't very likely to >>> happen. The only way to define these conversions would be through a >>> Wide_Wide_String intermediate - the net effect is that the conversions >>> will be quite expensive and you would never, ever want to use such >>> implementations. >> >> This is exactly the overhead of doing this using the infamous unary plus >> operation. I don't understand the point you are trying to make. You don't >> want to override for custom types, you don't want automatic conversion as >> too expensive. There is no third way. You want to apply explicit >> conversions at all call points? This is exactly the solution you declared >> inefficient. It not only inefficient, it is extremely error prone and a >> major overhead for those unfortunate who have to use the package defined >> in such manner. The compiler rejects a program. What you do? Erratically >> place unary pluses before all arguments? But that is invisible. Actually some >> hundred of them are already visible. For each of them the compiler spits >> some garbage error messages on you. But the right one you need is not >> visible. Were was it declared? Was it declared anywhere? Have fun! > > You're confusing expensive *implicit* operations with expensive explicit > ones. I don't care that an explicit type conversion is expensive -- you > wrote it, you meant it, and you can see the consequences -- it's right there > in the source code. Right, I don't care about performance I care about usability of the packages. Only when performance becomes a problem I address that. But I never let performance issues to cripple my design. But if performance is your concern, you must be the first to go for multi-methods, because this is the only way to define type-specific operations and to have different representations for different members of the hierarchy. Your proposal was to render all strings as Wide_Wide_String. And you tell me about efficiency? > For instance, I tend to write out the entire name of the conversion between > string and unbounded string: > > Ada.Text_IO.Put_Line (Ada.Strings.Unbounded.To_String (My_Object)); Hideous. What kind of information this mess should convey to the reader? 2/3 of it is noise. My_Object is a string, why Put_Line does not handle it? -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-11 7:59 ` Dmitry A. Kazakov @ 2013-04-11 11:10 ` Georg Bauhaus 2013-04-11 13:49 ` J-P. Rosen 2013-04-11 23:02 ` Randy Brukardt 2 siblings, 0 replies; 242+ messages in thread From: Georg Bauhaus @ 2013-04-11 11:10 UTC (permalink / raw) On 11.04.13 09:59, Dmitry A. Kazakov wrote: >>> You don't make language design dependent and promoting bad practices. >> > >> >If you are starting with a blank page, you're right. If you are building on >> >30+ years of practice, even "bad practice" has to be taken into account. > Nonsense. Bad practice is bad. Longer it lasts bigger is the damage. The consultancy business might be damaged as well when the language becomes simpler. Or maybe not? ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-11 7:59 ` Dmitry A. Kazakov 2013-04-11 11:10 ` Georg Bauhaus @ 2013-04-11 13:49 ` J-P. Rosen 2013-04-11 15:07 ` Dmitry A. Kazakov 2013-04-11 23:02 ` Randy Brukardt 2 siblings, 1 reply; 242+ messages in thread From: J-P. Rosen @ 2013-04-11 13:49 UTC (permalink / raw) Le 11/04/2013 09:59, Dmitry A. Kazakov a �crit : > type Complex is new Real with record > Img : Float; > end record; > > How is the compiler supposed to inherit "+"? The problem is not in the language. It is a wrong modelling, since a complex is not a specialisation of a real. -- J-P. Rosen Adalog 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00 http://www.adalog.fr ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-11 13:49 ` J-P. Rosen @ 2013-04-11 15:07 ` Dmitry A. Kazakov 2013-04-12 4:39 ` J-P. Rosen 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-11 15:07 UTC (permalink / raw) On Thu, 11 Apr 2013 15:49:03 +0200, J-P. Rosen wrote: > Le 11/04/2013 09:59, Dmitry A. Kazakov a �crit : >> type Complex is new Real with record >> Img : Float; >> end record; >> >> How is the compiler supposed to inherit "+"? > > The problem is not in the language. It is a wrong modelling, since a > complex is not a specialisation of a real. Type extension is not specialization either. Specialization in Ada is more or less covered by subtypes. [Type extension is Cartesian product.] -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-11 15:07 ` Dmitry A. Kazakov @ 2013-04-12 4:39 ` J-P. Rosen 2013-04-12 8:00 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: J-P. Rosen @ 2013-04-12 4:39 UTC (permalink / raw) Le 11/04/2013 17:07, Dmitry A. Kazakov a écrit : >> The problem is not in the language. It is a wrong modelling, since a >> > complex is not a specialisation of a real. > Type extension is not specialization either. > > Specialization in Ada is more or less covered by subtypes. [Type extension > is Cartesian product.] Well, every proponent of OO will claim that inheritance is about specialization. It seems to me that what you call Cartesian product is rather about composition. And subtypes have nothing to do specialization, at least as defined in conventional OO. -- J-P. Rosen Adalog 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00 http://www.adalog.fr ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-12 4:39 ` J-P. Rosen @ 2013-04-12 8:00 ` Dmitry A. Kazakov 2013-04-12 9:09 ` J-P. Rosen 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-12 8:00 UTC (permalink / raw) On Fri, 12 Apr 2013 06:39:24 +0200, J-P. Rosen wrote: > Le 11/04/2013 17:07, Dmitry A. Kazakov a écrit : >>> The problem is not in the language. It is a wrong modelling, since a >>> > complex is not a specialisation of a real. >> Type extension is not specialization either. >> >> Specialization in Ada is more or less covered by subtypes. [Type extension >> is Cartesian product.] > Well, every proponent of OO will claim that inheritance is about > specialization. Specialization constraints the domain set and/or operations, which is not the case with type extensions. Extensions are popular because they don't touch the domain set. As a Cartesian product the derived type provides a mapping to the original domain, you just drop the second member of the pair: (parent_part, extension_part) -> parent_part. This allows to inherit many operations, but not factories. Anyway it is easy to see that specialization breaks some operations too. The text book case is the circle-ellipse controversy. When you specialize ellipses to circles you break operations like Resize. Now, how the compiler is supposed to inherit that? Ada 95 design was absolutely sound and correct in that respect. I am really amazed that you and Randy propose to change that to unsafe and semantically broken behaviour, in order to reduce amount of typing? Is it serious, or just to counter me? -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-12 8:00 ` Dmitry A. Kazakov @ 2013-04-12 9:09 ` J-P. Rosen 2013-04-12 17:00 ` Jeffrey Carter 0 siblings, 1 reply; 242+ messages in thread From: J-P. Rosen @ 2013-04-12 9:09 UTC (permalink / raw) Le 12/04/2013 10:00, Dmitry A. Kazakov a écrit : > Ada 95 design was absolutely sound and correct in that respect. I am really > amazed that you and Randy propose to change that to unsafe and semantically > broken behaviour, in order to reduce amount of typing? Is it serious, or > just to counter me? I agree that the design is right, and I'm not proposing to change anything. I just said that the commonly accepted meaning of inheritence is specialization, where the upper level classes are more general and the lower ones are more specialized. I agree that inheritance has its own problems - that's why I use it rarely, I prefer composition. -- J-P. Rosen Adalog 2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00 http://www.adalog.fr ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-12 9:09 ` J-P. Rosen @ 2013-04-12 17:00 ` Jeffrey Carter 0 siblings, 0 replies; 242+ messages in thread From: Jeffrey Carter @ 2013-04-12 17:00 UTC (permalink / raw) On 04/12/2013 02:09 AM, J-P. Rosen wrote: > > I just said that the commonly accepted meaning of inheritence is > specialization, where the upper level classes are more general and the > lower ones are more specialized. I agree that inheritance has its own > problems - that's why I use it rarely, I prefer composition. While it's true that many proponents of type extension claim they're creating specialization classifications, starting with general classes and extending them to create more specialized ones, it's also demonstrably wrong in most cases: It's a rare specialization classification in which the more specialized classes need more data than the more general ones. In classifying plane figures, for example, the general classes (such as "polygon") clearly need more data in their representations than the specialized classes (such as "square"). Type extension starts with abstract classes, and extends them to create more concrete ones, a fact that Ada recognizes with its "abstract" reserved word. -- Jeff Carter "Why, the Mayflower was full of Fireflies, and a few horseflies, too. The Fireflies were on the upper deck, and the horseflies were on the Fireflies." Duck Soup 95 ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-11 7:59 ` Dmitry A. Kazakov 2013-04-11 11:10 ` Georg Bauhaus 2013-04-11 13:49 ` J-P. Rosen @ 2013-04-11 23:02 ` Randy Brukardt 2013-04-12 8:17 ` Dmitry A. Kazakov 2 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-04-11 23:02 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:1o34nhpfuy6yl$.2orlukd1elr7.dlg@40tude.net... > On Wed, 10 Apr 2013 17:07:57 -0500, Randy Brukardt wrote: > >> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message >> news:8bj2k30k7i19.w7ehsldwbf7x.dlg@40tude.net... >>> On Tue, 9 Apr 2013 18:24:29 -0500, Randy Brukardt wrote: >> ... >>>>> Why there should be many? >>>> >>>> If you've got operations like "+" or "*", you'll have a lot of >>>> functions >>>> returning objects of the type. That's a bad idea for the reasons I >>>> mentioned. >>> >>> You have + and * of GUI objects? That is weird. Anyway if you have >>> arithmetic upon a hierarchy how the compiler is supposed to deduce >>> implementations for derived types? >> >> Tagged types and extension is used for more than just GUIs. > > Tagged types are useless when arithmetic operations get involved. It does > not work with present design, because type hierarchies are not handled for > such operations. > >> The compiler shouldn't have trouble with inheriting implementations > > type Real is tagged record > Value : Float; > end record; > function "+" (L, R : Real) return Real; > > type Complex is new Real with record > Img : Float; > end record; > > How is the compiler supposed to inherit "+"? Easy, it uses the defined constructor. I explained that in the part of the message that you deleted. That's a feature Ada is missing but could easily have, especially as we already have something like it for null extensions. Of course, I don't think Float and Complex have enough in common for this sort of derivation to make sense. (The only commonality between float "*" and complex "*" is the name.) ... >>> You don't make language design dependent and promoting bad practices. >> >> If you are starting with a blank page, you're right. If you are building >> on >> 30+ years of practice, even "bad practice" has to be taken into account. > > Nonsense. Bad practice is bad. Longer it lasts bigger is the damage. Not nonsense. You can't break existing programs if you expect people to upgrade. I've got a million or so lines of Ada code; I can't use a new upgraded language on those if they are going to be broken, and I can't support a different compiler for every version of code ever written. If you can detect the "bad practice" at compile-time *and* its rare enough, then, and only then, can we consider an incompatibility. Differences at run-time are intolerable unless the likelihood of it occurring in practice are very small. We've made exceptions to that, but only after many attempts to adopt other solutions and a lot of research of existing databases of code. (And they're always controversial.) >> This is one of the reasons that the language you're suggesting really has >> to >> be different than Ada. > > We already discussed that. I want to preserve Ada semantics. It is you who > wants completely change the way string types are used in Ada. But you're not going to come close to preserving Ada semantics. The model of the language is a very important part of that semantics, as it is encoded in countless books and articles and tutorials. The gain from abandoning it (and we'd have to abandon it to adopt a model like yours) would have to be immense. ... >>>> That isn't very likely to >>>> happen. The only way to define these conversions would be through a >>>> Wide_Wide_String intermediate - the net effect is that the conversions >>>> will be quite expensive and you would never, ever want to use such >>>> implementations. >>> >>> This is exactly the overhead of doing this using the infamous unary plus >>> operation. I don't understand the point you are trying to make. You >>> don't >>> want to override for custom types, you don't want automatic conversion >>> as >>> too expensive. There is no third way. You want to apply explicit >>> conversions at all call points? This is exactly the solution you >>> declared >>> inefficient. It not only inefficient, it is extremely error prone and a >>> major overhead for those unfortunate who have to use the package defined >>> in such manner. The compiler rejects a program. What you do? Erratically >>> place unary pluses before all arguments? But that is invisible. Actually >>> some >>> hundred of them are already visible. For each of them the compiler spits >>> some garbage error messages on you. But the right one you need is not >>> visible. Were was it declared? Was it declared anywhere? Have fun! >> >> You're confusing expensive *implicit* operations with expensive explicit >> ones. I don't care that an explicit type conversion is expensive -- you >> wrote it, you meant it, and you can see the consequences -- it's right >> there >> in the source code. > > Right, I don't care about performance I care about usability of the > packages. Only when performance becomes a problem I address that. But I > never let performance issues to cripple my design. Fair enough, as I agree in general. But it is important, especially for embedded systems, that there is a correlation between the "expense" of the construct and how "expensive" it looks. I don't think expensive operations should occur automatically, especially if they're a dubious idea to begin with. > But if performance is your concern, you must be the first to go for > multi-methods, because this is the only way to define type-specific > operations and to have different representations for different members of > the hierarchy. Your proposal was to render all strings as > Wide_Wide_String. > And you tell me about efficiency? It is never a good idea to mix types in a program: String shouldn't be mixed with Wide_String, Float with Complex, or Integer with Float. In the rare case when you need to do so, you should write an explicit conversion. There's nothing wrong with storing all strings in unbounded UTF-8, for instance, but storing them in a variety of formats will just cause you a huge amount of translation overhead. It's not worth it. The Wide_Wide_Strings are only used for conversions between types and literals. (And for slice emulation, although I'm dubious that we need that; the operations in Ada.Strings.Fixed are easier to understand and use for most things.) >> For instance, I tend to write out the entire name of the conversion >> between >> string and unbounded string: >> >> Ada.Text_IO.Put_Line (Ada.Strings.Unbounded.To_String (My_Object)); > > Hideous. What kind of information this mess should convey to the reader? > 2/3 of it is noise. My_Object is a string, why Put_Line does not handle > it? It's a "string", not a String. Of course it shouldn't handle it. I'd like a shorter name for this conversion (preferably a user-defined type conversion), but I definitely do not want to get rid of it here. Ada.Text_IO.Put_Line (String (My_Object)); seems perfect. Of course, "General_Text_IO" would take Root_String'Class, so you could write what you want with it. Ada.General_Text_IO.Put_Line (My_Object); The internals of the Put_Line operation would be a lot more expensive in that case, whether that matters or not depends on the problem (probably not for Put_Line). Anyway, our programming styles are probably 180 degrees apart -- it's not surprising that we don't agree on any of this. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-11 23:02 ` Randy Brukardt @ 2013-04-12 8:17 ` Dmitry A. Kazakov 2013-04-12 9:41 ` Georg Bauhaus 2013-04-13 0:22 ` Randy Brukardt 0 siblings, 2 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-12 8:17 UTC (permalink / raw) On Thu, 11 Apr 2013 18:02:49 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:1o34nhpfuy6yl$.2orlukd1elr7.dlg@40tude.net... >> On Wed, 10 Apr 2013 17:07:57 -0500, Randy Brukardt wrote: >> >>> The compiler shouldn't have trouble with inheriting implementations >> >> type Real is tagged record >> Value : Float; >> end record; >> function "+" (L, R : Real) return Real; >> >> type Complex is new Real with record >> Img : Float; >> end record; >> >> How is the compiler supposed to inherit "+"? > > Easy, it uses the defined constructor. You must be joking. How the compiler knows how to add complex numbers? type Polar_Complex is new Real with record Angle : Float; end record; This one too? > Of course, I don't think Float and Complex have enough in common for this > sort of derivation to make sense. (The only commonality between float "*" > and complex "*" is the name.) The commonality is called "field": http://en.wikipedia.org/wiki/Field_%28mathematics%29 >>>> You don't make language design dependent and promoting bad practices. >>> >>> If you are starting with a blank page, you're right. If you are building >>> on 30+ years of practice, even "bad practice" has to be taken into account. >> >> Nonsense. Bad practice is bad. Longer it lasts bigger is the damage. > > Not nonsense. You can't break existing programs if you expect people to > upgrade. Show me a program that gets broken by introducing untagged classes. >> But if performance is your concern, you must be the first to go for >> multi-methods, because this is the only way to define type-specific >> operations and to have different representations for different members of >> the hierarchy. Your proposal was to render all strings as >> Wide_Wide_String. And you tell me about efficiency? > > It is never a good idea to mix types in a program: String shouldn't be mixed > with Wide_String, Float with Complex, or Integer with Float. In the rare > case when you need to do so, you should write an explicit conversion. Ergo, performance is not your concern when it is about the Principle. But you tried to justify that very principle with performance in first place. So, we are the to the square one. Why is it never a good idea to use Ada.Strings.Unbounded.Append [a mixed type operation]? > There's nothing wrong with storing all strings in unbounded UTF-8, for > instance, but storing them in a variety of formats will just cause you a > huge amount of translation overhead. It's not worth it. This is what you proposed. I did to avoid translations through support of mixed type operations. They do exactly that. >>> For instance, I tend to write out the entire name of the conversion >>> between string and unbounded string: >>> >>> Ada.Text_IO.Put_Line (Ada.Strings.Unbounded.To_String (My_Object)); >> >> Hideous. What kind of information this mess should convey to the reader? >> 2/3 of it is noise. My_Object is a string, why Put_Line does not handle >> it? > > It's a "string", not a String. And *semantically* the difference is? -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-12 8:17 ` Dmitry A. Kazakov @ 2013-04-12 9:41 ` Georg Bauhaus 2013-04-12 11:46 ` Dmitry A. Kazakov 2013-04-13 0:22 ` Randy Brukardt 1 sibling, 1 reply; 242+ messages in thread From: Georg Bauhaus @ 2013-04-12 9:41 UTC (permalink / raw) On 12.04.13 10:17, Dmitry A. Kazakov wrote: >>>> For instance, I tend to write out the entire name of the conversion >>>> >>>between string and unbounded string: >>>> >>> >>>> >>> Ada.Text_IO.Put_Line (Ada.Strings.Unbounded.To_String (My_Object)); >>> >> >>> >>Hideous. What kind of information this mess should convey to the reader? >>> >>2/3 of it is noise. My_Object is a string, why Put_Line does not handle >>> >>it? >> > >> >It's a "string", not a String. > And*semantically* the difference is? The difference is in the meaning that one assigns to "String". "One" refers to one of two minds performing the assignment: (a) he who considers a program as per how Ada is defined, literally. (b) he who considers a program in terms of definitions that underlie the the definition of Ada, though not literally. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-12 9:41 ` Georg Bauhaus @ 2013-04-12 11:46 ` Dmitry A. Kazakov 2013-04-13 17:38 ` Georg Bauhaus 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-12 11:46 UTC (permalink / raw) On Fri, 12 Apr 2013 11:41:25 +0200, Georg Bauhaus wrote: > On 12.04.13 10:17, Dmitry A. Kazakov wrote: >>>>> For instance, I tend to write out the entire name of the conversion >>>>> >>>between string and unbounded string: >>>>> >>> >>>>> >>> Ada.Text_IO.Put_Line (Ada.Strings.Unbounded.To_String (My_Object)); >>>> >> >>>> >>Hideous. What kind of information this mess should convey to the reader? >>>> >>2/3 of it is noise. My_Object is a string, why Put_Line does not handle >>>> >>it? >>> > >>> >It's a "string", not a String. >> And*semantically* the difference is? > > The difference is in the meaning that one assigns to "String". > "One" refers to one of two minds performing the assignment: > > (a) he who considers a program as per how Ada is defined, > literally. > > (b) he who considers a program in terms of definitions that > underlie the the definition of Ada, though not literally. I gather that in your opinion: 1. There is no semantic difference between String and Unbounded_String. 2. Somehow from literal and non-literal considerations it follows that Ada.Text_IO.Put_Line (Ada.Strings.Unbounded.To_String (My_Object)); is better/clearer/safer/more efficient than Ada.Text_IO.Put_Line (My_Object); How exactly Put_Line is good with String and bad with Unbounded_String? -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-12 11:46 ` Dmitry A. Kazakov @ 2013-04-13 17:38 ` Georg Bauhaus 0 siblings, 0 replies; 242+ messages in thread From: Georg Bauhaus @ 2013-04-13 17:38 UTC (permalink / raw) On 12.04.13 13:46, Dmitry A. Kazakov wrote: > On Fri, 12 Apr 2013 11:41:25 +0200, Georg Bauhaus wrote: > >> On 12.04.13 10:17, Dmitry A. Kazakov wrote: >>>>>> For instance, I tend to write out the entire name of the conversion >>>>>>>>> between string and unbounded string: >>>>>>>>> >>>>>>>>> Ada.Text_IO.Put_Line (Ada.Strings.Unbounded.To_String (My_Object)); >>>>>>> >>>>>>> Hideous. What kind of information this mess should convey to the reader? >>>>>>> 2/3 of it is noise. My_Object is a string, why Put_Line does not handle >>>>>>> it? >>>>> >>>>> It's a "string", not a String. >>> And*semantically* the difference is? >> >> The difference is in the meaning that one assigns to "String". >> "One" refers to one of two minds performing the assignment: >> >> (a) he who considers a program as per how Ada is defined, >> literally. >> >> (b) he who considers a program in terms of definitions that >> underlie the the definition of Ada, though not literally. > > I gather that in your opinion: > > 1. There is no semantic difference between String and Unbounded_String. The difference is between definitions of semantics (sic), I said. Semantics is not an absolute. So the meaning of "string" depends on the assignment of meaning to "string". Here is where there is a difference. It is an interesting one. I have not made any value judgments. One vague hint is a what "string" means is in a certain view of Put. Another equally rational reference to definitions says that Ada defines String to be this-and-that, and nothing else. Both are assignments of meaning to "string". Both are rational. They differ, usefully. For the sake of an example, let array interfaces be a related issue. Then, in order to remove all the fog, unveil the statue, just outline, en detail, for compiler-aware dummies, step by step, how a compiler would check the user defined array thing for correctness, Ada style, producing suitable calls of suitably checked user-supplied array operations, compatible with uses of arrays in places where they can be used today. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-12 8:17 ` Dmitry A. Kazakov 2013-04-12 9:41 ` Georg Bauhaus @ 2013-04-13 0:22 ` Randy Brukardt 2013-04-13 6:49 ` Dmitry A. Kazakov 1 sibling, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-04-13 0:22 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:lhy7cs9p0v0t.jmyir4bofwok.dlg@40tude.net... > On Thu, 11 Apr 2013 18:02:49 -0500, Randy Brukardt wrote: ... >> It is never a good idea to mix types in a program: String shouldn't be >> mixed >> with Wide_String, Float with Complex, or Integer with Float. In the rare >> case when you need to do so, you should write an explicit conversion. > > Ergo, performance is not your concern when it is about the Principle. But > you tried to justify that very principle with performance in first place. > > So, we are the to the square one. Of course. You argue in circles, which makes me go over the same things over and over. I'm wasting my time bothering. > Why is it never a good idea to use > Ada.Strings.Unbounded.Append [a mixed type operation]? That's the package that convinced me that mixed operations are never a good idea. The intent of the mixed operations was to provide string literals, but the effect was that they are available inconsistently and you're at a real risk of ambiguity. Moreover, there are cases where you have to convert things to String just to do an operation on a value of an Unbounded_String. It's just a bad design. Of course, if you have to use the bad design, then using the operations provided in that bad design is unavoidable. >> There's nothing wrong with storing all strings in unbounded UTF-8, for >> instance, but storing them in a variety of formats will just cause you a >> huge amount of translation overhead. It's not worth it. > > This is what you proposed. I did to avoid translations through support of > mixed type operations. They do exactly that. But you're not eliminating anything. The only way to implement such mixed operations is via converting one or the other operands to the most general type. Certainly that's required to automatically create such operations, and that would have to be the case in order to avoid forcing programmers to create thousands of operations for large hierarchies like strings. In any case, multi-methods don't work given the existing Ada resolution rules. You want to fix that with preference rules, but those are a non-starter. That's because preference rules give rise to Ripple and Beaujolias effects, which are not and will not be tolerated in Ada. (These are cases where adding or removing an otherwise unused with or use clause can change the meaning of a program.) Unless you can clearly prove that you have rules that are completely free of such effects (which are significant maintenance hazards), the ARG will not consider them. (Integrated packages failed in Ada 2012 mainly because we couldn't eliminate such effects.) >>>> For instance, I tend to write out the entire name of the conversion >>>> between string and unbounded string: >>>> >>>> Ada.Text_IO.Put_Line (Ada.Strings.Unbounded.To_String (My_Object)); >>> >>> Hideous. What kind of information this mess should convey to the reader? >>> 2/3 of it is noise. My_Object is a string, why Put_Line does not handle >>> it? >> >> It's a "string", not a String. > > And *semantically* the difference is? Ada is strongly typed; there is currently no such thing as an operation that will work on any string type. The origin of this pointless discussion was possible ways to fix that, but you are so focused on useless, pie-in-the-sky capabilities that we can't sanely explore what we CAN do. (Which is what I wanted to do initially.) Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-13 0:22 ` Randy Brukardt @ 2013-04-13 6:49 ` Dmitry A. Kazakov 2013-04-16 1:41 ` Randy Brukardt 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-13 6:49 UTC (permalink / raw) On Fri, 12 Apr 2013 19:22:36 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:lhy7cs9p0v0t.jmyir4bofwok.dlg@40tude.net... >> On Thu, 11 Apr 2013 18:02:49 -0500, Randy Brukardt wrote: > ... >> Why is it never a good idea to use >> Ada.Strings.Unbounded.Append [a mixed type operation]? > > That's the package that convinced me that mixed operations are never a good > idea. The intent of the mixed operations was to provide string literals, but > the effect was that they are available inconsistently and you're at a real > risk of ambiguity. Moreover, there are cases where you have to convert > things to String just to do an operation on a value of an Unbounded_String. > It's just a bad design. And the solution is to remove Append? What would be a "good" design of Unbounded_String and String such that you never mixed them? Is there any? You missing the main point that whatever difference Unbounded_String and String may have, it is not a semantic difference. Both are different implementations of the same thing. They are mixed right from the start. >>> There's nothing wrong with storing all strings in unbounded UTF-8, for >>> instance, but storing them in a variety of formats will just cause you a >>> huge amount of translation overhead. It's not worth it. >> >> This is what you proposed. I did to avoid translations through support of >> mixed type operations. They do exactly that. > > But you're not eliminating anything. The only way to implement such mixed > operations is via converting one or the other operands to the most general > type. Wrong, a multi-method has a body for each combination of parameters. > In any case, multi-methods don't work given the existing Ada resolution > rules. You want to fix that with preference rules, but those are a > non-starter. You cannot know that without even trying to consider these rules or alternatives to them. > Unless you can clearly prove that you have rules that are completely free of > such effects (which are significant maintenance hazards), the ARG will not > consider them. Sure it will not. >>>>> For instance, I tend to write out the entire name of the conversion >>>>> between string and unbounded string: >>>>> >>>>> Ada.Text_IO.Put_Line (Ada.Strings.Unbounded.To_String (My_Object)); >>>> >>>> Hideous. What kind of information this mess should convey to the reader? >>>> 2/3 of it is noise. My_Object is a string, why Put_Line does not handle >>>> it? >>> >>> It's a "string", not a String. >> >> And *semantically* the difference is? > > Ada is strongly typed; there is currently no such thing as an operation that > will work on any string type. This is why I am asking this question. Where is a semantic difference to justify the choice to draw a firewall between String and Unbounded_String? -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-13 6:49 ` Dmitry A. Kazakov @ 2013-04-16 1:41 ` Randy Brukardt 2013-04-16 8:03 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-04-16 1:41 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:gj0dksp3fqws$.15ahjs6oqwquj.dlg@40tude.net... > On Fri, 12 Apr 2013 19:22:36 -0500, Randy Brukardt wrote: ... > And the solution is to remove Append? What would be a "good" design of > Unbounded_String and String such that you never mixed them? Is there any? Not remove Append, but remove the version of Append that mixes two different types. The only operations that change types should be explicit conversions (possibly user-defined versions of that, using functions). > You missing the main point that whatever difference Unbounded_String and > String may have, it is not a semantic difference. Both are different > implementations of the same thing. They are mixed right from the start. Representation is an integral part of semantics. I strongly disagree that they're representations of the same thing, because that would imply that they do exactly the same thing for all operations -- and that's clearly not true. And this is crux of the issue -- we simply do not agree at this fundamental level about this topic, and I can't imagine any reason that either of us will change our positions here. So we're both wasting our time. ... >>> This is what you proposed. I did to avoid translations through support >>> of >>> mixed type operations. They do exactly that. >> >> But you're not eliminating anything. The only way to implement such mixed >> operations is via converting one or the other operands to the most >> general >> type. > > Wrong, a multi-method has a body for each combination of parameters. > >> In any case, multi-methods don't work given the existing Ada resolution >> rules. You want to fix that with preference rules, but those are a >> non-starter. > > You cannot know that without even trying to consider these rules or > alternatives to them. We've tried such rules to solve other problems several times in the past. They've almost never worked. And I don't care to try, I see no problem with the current state of affairs. It's on you to come up with a worked-out solution that you can propose. Otherwise, I'm certain that nothing you want to see will happen -- it isn't happening by magic. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-16 1:41 ` Randy Brukardt @ 2013-04-16 8:03 ` Dmitry A. Kazakov 2013-04-16 22:57 ` Randy Brukardt 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-16 8:03 UTC (permalink / raw) On Mon, 15 Apr 2013 20:41:46 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:gj0dksp3fqws$.15ahjs6oqwquj.dlg@40tude.net... >> On Fri, 12 Apr 2013 19:22:36 -0500, Randy Brukardt wrote: > ... >> And the solution is to remove Append? What would be a "good" design of >> Unbounded_String and String such that you never mixed them? Is there any? > > Not remove Append, but remove the version of Append that mixes two different > types. OK, that is not serious. > The only operations that change types should be explicit conversions > (possibly user-defined versions of that, using functions). Conversions are mixed type operations per definition: function "+" (Value : String) return Unbounded_String; is mixed, and additionally a multi-method if String and Unbounded_String in the same hierarchy with "+" defined there. >> You missing the main point that whatever difference Unbounded_String and >> String may have, it is not a semantic difference. Both are different >> implementations of the same thing. They are mixed right from the start. > > Representation is an integral part of semantics. I don't understand why you are using Ada then. There are lots of great languages which pursue the principle that representation is semantics, beginning with C. > I strongly disagree that > they're representations of the same thing, because that would imply that > they do exactly the same thing for all operations -- and that's clearly not > true. That is certainly true. All operations of these types deal with exactly same thing called "string." Whatever difference existed is motivated solely by implementation reasons, e.g. by memory management issues. These are irrelevant to what string is: a sequence of code points with operations like (), &, <, <=, Put_Line etc. > I'm certain that nothing you want > to see will happen -- it isn't happening by magic. Clearly so, when even separation of implementation and interface is no more considered Ada's design principle. I have no illusions. The trend is obvious when looking at Ada 2005 and 2012. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-16 8:03 ` Dmitry A. Kazakov @ 2013-04-16 22:57 ` Randy Brukardt 2013-04-17 7:18 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-04-16 22:57 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:144bgnv8rdks7$.1o76z1eh196ks$.dlg@40tude.net... > On Mon, 15 Apr 2013 20:41:46 -0500, Randy Brukardt wrote: ... >>> You missing the main point that whatever difference Unbounded_String and >>> String may have, it is not a semantic difference. Both are different >>> implementations of the same thing. They are mixed right from the start. >> >> Representation is an integral part of semantics. > > I don't understand why you are using Ada then. There are lots of great > languages which pursue the principle that representation is semantics, > beginning with C. Representation is not semantics -- it's *part* of semantics -- there are other components to semantics as well, which languages like C ignore. But you're ignoring the part of semantics that is associated with representation, and that's just as bad. One type for one purpose. If you think you need different representations for a type, you're clearly mixing purposes and that's bad. Anyway, I use Ada because it forces me to write precisely and it complains about any abuse of types. And because it has the most sensible syntax of any language that I've been seriously exposed to. And most of all, because it automatically includes lots of dynamic checks to prevent mistakes from spreading (I hate debugging). The latter two are the most important, and they are only tangentially involved with types. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-16 22:57 ` Randy Brukardt @ 2013-04-17 7:18 ` Dmitry A. Kazakov 2013-04-17 9:23 ` Georg Bauhaus 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-17 7:18 UTC (permalink / raw) On Tue, 16 Apr 2013 17:57:20 -0500, Randy Brukardt wrote: > One type for one purpose. If you think you need different representations > for a type, you're clearly mixing purposes and that's bad. This is deeply wrong. In software engineering we have functional and non-functional requirements to deal with the situation that no computing system can adequately reflect the problem space. Semantics is functional. Representation is non-functional and to large extent arbitrary. This is why same things can and must be implemented differently using different representations and different algorithms for its operations within the same system. Which is why Ada has infinite number of string types (counting bounded strings) which serve single purpose of dealing with sequences of characters. If you think otherwise your proposal should be a universal string type suitable for all systems from tiny embedded targets, for all memory management strategies, for all types of encoding, for all character sets. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-17 7:18 ` Dmitry A. Kazakov @ 2013-04-17 9:23 ` Georg Bauhaus 2013-04-17 9:57 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Georg Bauhaus @ 2013-04-17 9:23 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote: >. > Representation is non-functional and to large extent arbitrary. The functional specification may refer to TIME and SPACE in essential ways, giving precise declarations of what is not to be exceeded. Within the formal limits and possibilities of the system given, this requires judicious use of, well, what, if the programmer must not declare some sort of representations? How does a type cover essential behavioral aspects of time and space if representation may not be part of the type system? If the Ada type system cannot express time and space, I'll still consider them functional requirements. And I'd much rather want the types to state them, rather than hands waving stories about implementations. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-17 9:23 ` Georg Bauhaus @ 2013-04-17 9:57 ` Dmitry A. Kazakov 2013-04-17 19:38 ` Georg Bauhaus 0 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-17 9:57 UTC (permalink / raw) On 17 Apr 2013 09:23:26 GMT, Georg Bauhaus wrote: > How does a type cover essential behavioral > aspects of time and space if representation > may not be part of the type system? Representation clauses for task types, memory layout of the TCB? (:-)) > If the Ada type system cannot express > time and space, I'll still consider them > functional requirements. And this should justify conflation of a representation with the type semantics... surely. > And I'd much rather > want the types to state them, rather than > hands waving stories about implementations. Excellent, A.4.5: package Ada.Strings.Unbounded is type Unbounded_String is private; This sort of thing of representation declaration? It is always interesting to observe the ends people are ready to go defending undefendable... -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-17 9:57 ` Dmitry A. Kazakov @ 2013-04-17 19:38 ` Georg Bauhaus 2013-04-18 11:52 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Georg Bauhaus @ 2013-04-17 19:38 UTC (permalink / raw) On 17.04.13 11:57, Dmitry A. Kazakov wrote: >> If the Ada type system cannot express >> time and space, I'll still consider them >> functional requirements. > > And this should justify conflation of a representation with the type > semantics... surely. Representation is functional, like it or not, and it is meaningful, therefore it is semantically important. Nothing is conflated here because semantics is assignment of meaning, not just types-whatever. Provide a different hook for stating functionally important representation and programmers might use it. For example, for this: "Make X a Θ(1) data structure of equally shaped objects of the same subtype, of a certain finite length, indexed by certain discrete values, components well aligned." For sure, type semantics, if that restriction should so easily mean a thing in a real-world programming language, isn't semantics. The meaning of an Ada program, for example, is determined by the implementation (RM 1.1.3). Period. That's also true in other languages. But I can be certain to get the Θ(1) thing mentioned above by making the necessary declarations in Ada, because of the meaning it assigns to "array". String is a good example. String is an array, and nothing else. The existence of RM A.4.({4,5}) is of no consequence. To hell with it. The existence of RM 3.6 is essential, because of array semantics. (And I don't care much about string literals because many are read from external sources during start-up. YMMV.) The only important type for text processing for me is the universal type to be used for defining text character types, because ranges of characters match notions relating to text just like ranges of whole numbers match notions relating to mathematical integers. There are excellent libraries full of text processing operations. If they give rise to universally good operators, excellent! If they need to involve representation, then so be it. I live in and off dirt, not mathematical purity, so long as the latter offers no way to denote functional requirements such as representing objects. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-17 19:38 ` Georg Bauhaus @ 2013-04-18 11:52 ` Dmitry A. Kazakov 2013-04-19 2:16 ` Randy Brukardt 2013-04-19 9:07 ` Georg Bauhaus 0 siblings, 2 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-18 11:52 UTC (permalink / raw) On Wed, 17 Apr 2013 21:38:28 +0200, Georg Bauhaus wrote: > On 17.04.13 11:57, Dmitry A. Kazakov wrote: > >>> If the Ada type system cannot express >>> time and space, I'll still consider them >>> functional requirements. >> >> And this should justify conflation of a representation with the type >> semantics... surely. > > Representation is functional, You should feel obliged to write an AI to disband ARM 7.3. > Nothing is conflated here because semantics is assignment of meaning, http://en.wikipedia.org/wiki/Semantics > String is a good example. String is an array, and nothing else. Wrong. String has an array interface. In fact it has at least two array interfaces one of character/code points, another of encoding units. Operations like Find can be considered a third array interface. In many languages strings can be indexed by strings. > The existence of RM A.4.({4,5}) is of no consequence. To hell with it. In that case show us a way to create unbounded arrays with representation guts inside out. Your concept simply does not hold. There are simple indisputable facts: 1. The representation of string object is irrelevant to what string is. 2. It is impossible to have one implementation suitable for all string objects and all application domains that use strings, e.g. DNA sequencing, pattern matching, text processing, compiler construction etc. > The existence of RM 3.6 is essential, because of array semantics. Array semantics? What's that? You claimed that semantics is representation. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-18 11:52 ` Dmitry A. Kazakov @ 2013-04-19 2:16 ` Randy Brukardt 2013-04-19 7:39 ` Dmitry A. Kazakov 2013-04-19 9:07 ` Georg Bauhaus 1 sibling, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-04-19 2:16 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:qtagj9gwjjxn$.ljj8purwznkr.dlg@40tude.net... ... > Your concept simply does not hold. There are simple indisputable facts: > > 1. The representation of string object is irrelevant to what string is. This is clearly false, so it's pretty clear why you end up with bizarre conclusions. Specifically, the number of characters that a string object can hold (and whether that number can change, and by how much) is *indisputably* a critical part of string object semantics. This is so tightly interwined by the underlying representation (when you chose one, you pretty much chose the other) that practically it is inseparable. It's certainly true that you can have an abstract string interface that doesn't expose the representation -- that's the idea behind my Root_String'Class proposal -- and that's useful in a limited set of circumstances (mostly in read-only situations, which is the majority of string operations anyway). But it does not describe the complete semantics of a string object, nor could it. > 2. It is impossible to have one implementation suitable for all string > objects and all application domains that use strings, e.g. DNA sequencing, > pattern matching, text processing, compiler construction etc. Of course. So what? That's why we want a variety of string types for different jobs. That gives no reason why anyone should be mixing them! What do you get when you concatenate a DNA sequence and an Ada identifier? A bug! :-) Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-19 2:16 ` Randy Brukardt @ 2013-04-19 7:39 ` Dmitry A. Kazakov 0 siblings, 0 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-19 7:39 UTC (permalink / raw) On Thu, 18 Apr 2013 21:16:58 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:qtagj9gwjjxn$.ljj8purwznkr.dlg@40tude.net... > ... >> Your concept simply does not hold. There are simple indisputable facts: >> >> 1. The representation of string object is irrelevant to what string is. > > This is clearly false, so it's pretty clear why you end up with bizarre > conclusions. http://en.wikipedia.org/wiki/String_%28computer_science%29 > Specifically, the number of characters that a string object can hold (and > whether that number can change, and by how much) is *indisputably* a > critical part of string object semantics. Confusing semantics of objects with semantics of values they hold? Anyway your argument is evidently bogus as follows from: X : constant Unbounded_String := whatever; Is X a string object? Can you change the number of characters in there? Does it have a different representation? Do you care if it does? > It's certainly true that you can have an abstract string interface that > doesn't expose the representation -- that's the idea behind my > Root_String'Class proposal -- and that's useful in a limited set of > circumstances (mostly in read-only situations, which is the majority of > string operations anyway). But it does not describe the complete semantics > of a string object, nor could it. "Complete semantics" (whatever it means) /= string semantics. >> 2. It is impossible to have one implementation suitable for all string >> objects and all application domains that use strings, e.g. DNA sequencing, >> pattern matching, text processing, compiler construction etc. > > Of course. So what? Multiple string types => have to mix them [in the contexts where only string semantics is relevant] > That's why we want a variety of string types for > different jobs. That gives no reason why anyone should be mixing them! It is the reason, because otherwise you must show that no program can do more than one job ever. > What > do you get when you concatenate a DNA sequence and an Ada identifier? Meaningless question as there is no string type of Ada identifiers. Are you arguing that Ada identifiers require a special representation? A different representation from C identifiers? Are you saying that some string types shall not be mixed? Remember our discussion about cloning types? This has nothing to do with representations: type Ada_Identifier is new String; type C_Identifier is new String; The representation is same. Types are different. String semantics is same. Semantics relevant to compiler/parser construction could be same or different depending on the circumstances. You cannot determine this at the language level. You shall leave that to the programmer. It is his decision only whether types he designs to be mixed or not. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-18 11:52 ` Dmitry A. Kazakov 2013-04-19 2:16 ` Randy Brukardt @ 2013-04-19 9:07 ` Georg Bauhaus 2013-04-19 9:11 ` Georg Bauhaus 2013-04-19 12:09 ` Dmitry A. Kazakov 1 sibling, 2 replies; 242+ messages in thread From: Georg Bauhaus @ 2013-04-19 9:07 UTC (permalink / raw) On 18.04.13 13:52, Dmitry A. Kazakov wrote: > On Wed, 17 Apr 2013 21:38:28 +0200, Georg Bauhaus wrote: > >> On 17.04.13 11:57, Dmitry A. Kazakov wrote: >> >>>> If the Ada type system cannot express >>>> time and space, I'll still consider them >>>> functional requirements. >>> >>> And this should justify conflation of a representation with the type >>> semantics... surely. >> >> Representation is functional, > > You should feel obliged to write an AI to disband ARM 7.3. Semantics is not restricted to private types. Neither is any of the perspectives on semantics demonstrably more important, so much more important that other perspective do not matter to programmers (or language designers, I'd think). >> Nothing is conflated here because semantics is assignment of meaning, > > http://en.wikipedia.org/wiki/Semantics Yes, you might want to read it once more: "Semantics (from Ancient Greek: σημαντικός sēmantikós) is the study of meaning. It focuses on the relation between signifiers, like words, phrases, signs, and symbols, and what they stand for, their denotation." Thus, a functional requirement can be expressed as for A'Component_Size use 24; -- needed for CRM 114 and that which this declaration stands for is a consequence of Ada. It is much less a consequence of what a delighted mind might otherwise read into it, however spirited that other meaning may be. Semantics is not restricted to private types. Some things are language defined. >> String is a good example. String is an array, and nothing else. > > Wrong. String has an array interface. No, right. String has the "interface" of array. Period. Some intellectual type that some people may want to call "string" has some other properties. I may want to call this type Egg. Clearly, it is not a string then, right? Conversely, not everything that is called "string" is well defined because it someone calls it "string". > Operations like Find can be considered a third array interface. Confusion starts precisely from considering the mix of language defined semantics and used defined types. Go ahead. Tell us how a compiler will check the consistency of used defined array types with built-in arrays in all required places in Ada programs; then, suggesting a different array facility for Ada might be more convincing. > In many > languages strings can be indexed by strings. Show me one, I'm curios. Hashing is not indexing by strings, because hashing means computing a non-string that is to be used as the index value. The same is true for computing a position number for a find. >> The existence of RM A.4.({4,5}) is of no consequence. To hell with it. > > In that case show us a way to create unbounded arrays with representation > guts inside out. Ada does not have unbounded arrays and is not going to have them, I dare say. Instead, I suggest that you focus on creating/stealing types useful for text processing, and make them very different---unless you can finally produce a user-definable array facility 100% compatible with the known Ada array facility. Their only relation to current String (the current array) should be subprograms for conversion. How about that? > Your concept simply does not hold. There are simple indisputable facts: > > 1. The representation of string object is irrelevant to what string is. Again, an occurrence of, and stipulation of truth in, the auxiliary verb "is", without offering the necessary definitions of (a) its meaning, (b) a proof of concept. > 2. It is impossible to have one implementation suitable for all string > objects and all application domains that use strings, e.g. DNA sequencing, > pattern matching, text processing, compiler construction etc. Yes, the impossible string. And equally unlikely, there will be "whatever-way-generic" types that have substitutable sets of operations suitable for all "string processing". (Should the Find operation be required to be stateful so that it can be used in a lazy iteration scheme? Why? Why not?) >> The existence of RM 3.6 is essential, because of array semantics. > > Array semantics? What's that? When I declare an array type, RM 3.6 instructs about the meaning. > You claimed that semantics is representation. Again, a nice occurrence of a rhetorical classic. I said, instead: "Representation ... is meaningful, therefore it is semantically important." "semantics is assignment of meaning," http://en.wikipedia.org/wiki/Semantics ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-19 9:07 ` Georg Bauhaus @ 2013-04-19 9:11 ` Georg Bauhaus 2013-04-19 12:09 ` Dmitry A. Kazakov 1 sibling, 0 replies; 242+ messages in thread From: Georg Bauhaus @ 2013-04-19 9:11 UTC (permalink / raw) On 19.04.13 11:07, Georg Bauhaus wrote: > > Confusion starts precisely from considering the mix of language > defined semantics and used defined types. I'll correct a typo in the sentence because it (the sentence) is important to me. Confusion starts precisely from considering the mix of language defined semantics and user defined types. > Go ahead. Tell us how a compiler will check the consistency > of user defined array types with built-in arrays in all required > places in Ada programs; then, suggesting a different array > facility for Ada might be more convincing. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-19 9:07 ` Georg Bauhaus 2013-04-19 9:11 ` Georg Bauhaus @ 2013-04-19 12:09 ` Dmitry A. Kazakov 2013-04-19 22:14 ` Randy Brukardt 1 sibling, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-19 12:09 UTC (permalink / raw) On Fri, 19 Apr 2013 11:07:05 +0200, Georg Bauhaus wrote: > On 18.04.13 13:52, Dmitry A. Kazakov wrote: >> On Wed, 17 Apr 2013 21:38:28 +0200, Georg Bauhaus wrote: >> >>> On 17.04.13 11:57, Dmitry A. Kazakov wrote: >>> >>>>> If the Ada type system cannot express >>>>> time and space, I'll still consider them >>>>> functional requirements. >>>> >>>> And this should justify conflation of a representation with the type >>>> semantics... surely. >>> >>> Representation is functional, >> >> You should feel obliged to write an AI to disband ARM 7.3. > > Semantics is not restricted to private types. Private types have no semantics? Hint: language semantics /= program semantics >>> Nothing is conflated here because semantics is assignment of meaning, >> >> http://en.wikipedia.org/wiki/Semantics > > Yes, you might want to read it once more: > > "Semantics (from Ancient Greek: σημαντικός sēmantikós) is the study of > meaning. It focuses on the relation between signifiers, like words, > phrases, signs, and symbols, and what they stand for, their denotation." Semantics is not assignment of meaning. "Assignment of meaning" is an act of translation, understanding, cognition. >>> String is a good example. String is an array, and nothing else. >> >> Wrong. String has an array interface. > > No, right. String has the "interface" of array. Period. has /= is >> Operations like Find can be considered a third array interface. > > Confusion starts precisely from considering the mix of language > defined semantics and used defined types. Confusion of what with what? > Go ahead. Tell us how a compiler will check the consistency > of used defined array types with built-in arrays in all required > places in Ada programs; What is consistency of types and why the compiler must check it. Ada RM is silent about that. Anyway, normally, in formal systems or semi-formal ones like Ada programming language is, consistency (using standard meaning of this word) is guaranteed per construction of corresponding entities. Though I don't see how all this is related to array interfaces, built-in or not arrays, string types etc. There are certain requirements any implementation of array interface has to obey. Those are customary written in the RM under "implementation requirements" clauses. >> In many languages strings can be indexed by strings. > > Show me one, http://en.wikipedia.org/wiki/Associative_array >>> The existence of RM A.4.({4,5}) is of no consequence. To hell with it. >> >> In that case show us a way to create unbounded arrays with representation >> guts inside out. > > Ada does not have unbounded arrays and is not going to have them, Thus either your statement that string is an array is wrong or else Unbounded_Array is not string. The choice is yours. > I dare say. Instead, I suggest that you focus on creating/stealing types > useful for text processing, and make them very different---unless you > can finally produce a user-definable array facility 100% compatible > with the known Ada array facility. Their only relation to current String > (the current array) should be subprograms for conversion. How about > that? No idea. The question was how to implement unbounded strings exposing the representation. Do that first. Then the second question would be why on earth one should expose such a representation. The third question is why the RM should mandate this representation prohibiting other representations. >> Your concept simply does not hold. There are simple indisputable facts: >> >> 1. The representation of string object is irrelevant to what string is. > > Again, an occurrence of, and stipulation of truth in, the auxiliary > verb "is", without offering the necessary definitions of (a) its meaning, > (b) a proof of concept. Please, explain how representation aspects are relevant to the notion of strings in programming. That requires, in particular, a proof that all programming languages that deploy strings necessarily use same representation of. >> 2. It is impossible to have one implementation suitable for all string >> objects and all application domains that use strings, e.g. DNA sequencing, >> pattern matching, text processing, compiler construction etc. > > Yes, the impossible string. q.e.d. >>> The existence of RM 3.6 is essential, because of array semantics. >> >> Array semantics? What's that? > > When I declare an array type, RM 3.6 instructs about the meaning. Which is? You are confusing language semantics with program semantics. >> You claimed that semantics is representation. > > Again, a nice occurrence of a rhetorical classic. I said, instead: > > "Representation ... is meaningful, therefore it is semantically important." > "semantics is assignment of meaning," So representation is not semantics/meaning, at least to the programmer, of course, not to the hardware running the program, not to the artist using code printouts as tapestry patterns etc. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-19 12:09 ` Dmitry A. Kazakov @ 2013-04-19 22:14 ` Randy Brukardt 2013-04-20 6:39 ` Dmitry A. Kazakov 0 siblings, 1 reply; 242+ messages in thread From: Randy Brukardt @ 2013-04-19 22:14 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:84dn4lxu5j$.1mi40bvj8e8tc$.dlg@40tude.net... > On Fri, 19 Apr 2013 11:07:05 +0200, Georg Bauhaus wrote: ... >> "Representation ... is meaningful, therefore it is semantically >> important." >> "semantics is assignment of meaning," > > So representation is not semantics/meaning, at least to the programmer, of > course, not to the hardware running the program, not to the artist using > code printouts as tapestry patterns etc. Ah, now we get to the root of the problem. We're talking about Ada programming language design here, so when I talk about "semantics", I'm talking about the semantics of the Ada programming language, as specified in the Ada standard. I'm not talking about whatever ideas - quite possibly incorrect - that the programmer might have about how their program works. Those could be anything at all, and much like theology, cannot be usefully reasoned about. I've had plenty of misconceptions about Ada myself, even now. Not much point in discussing programmers views (beyond what we would LIKE them to be) when discussing detailed semantics. When you ask: > Confusing semantics of objects with semantics of values they hold? you're demonstrating *your* confusion. We're talking about string objects here. And Ada doesn't have composite values; there are only objects. There are no semantics of composite values, so it's impossible to confuse them with something that does exist. You then go on to say that the existence of different types requires mixing and then at the same time says that different types surely must be kept separate even if the representation is the same. You're essentially arguing both sides of this argument at the same time. One last time: I agree there is value to "generic" (English, not Ada meaning) operations for types. I don't consider such operations "mixing". And occassionally you'll need to explicitly convert one type to another. But that's it. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-04-19 22:14 ` Randy Brukardt @ 2013-04-20 6:39 ` Dmitry A. Kazakov 0 siblings, 0 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-04-20 6:39 UTC (permalink / raw) On Fri, 19 Apr 2013 17:14:52 -0500, Randy Brukardt wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message > news:84dn4lxu5j$.1mi40bvj8e8tc$.dlg@40tude.net... >> On Fri, 19 Apr 2013 11:07:05 +0200, Georg Bauhaus wrote: > ... >>> "Representation ... is meaningful, therefore it is semantically >>> important." >>> "semantics is assignment of meaning," >> >> So representation is not semantics/meaning, at least to the programmer, of >> course, not to the hardware running the program, not to the artist using >> code printouts as tapestry patterns etc. > > Ah, now we get to the root of the problem. We're talking about Ada > programming language design here, so when I talk about "semantics", I'm > talking about the semantics of the Ada programming language, as specified in > the Ada standard. So you are talking a tautology that the machine executes the program according to the language standard. Which is completely irrelevant to the issue, which is how programs are designed and what is required from the language side to support this activity. >> Confusing semantics of objects with semantics of values they hold? > > you're demonstrating *your* confusion. We're talking about string objects > here. And Ada doesn't have composite values; there are only objects. Yes, this is the core of your confusion. You conflate language semantics with program semantics. String is a problem space entity. The language may have some built-in types or means in order to model strings. These types are strings so long they model what programmers call "string." No longer. If for whatever reason there must be more than one type to model the same thing [string] these types must be mixed. > You then go on to say that the existence of different types requires mixing > and then at the same time says that different types surely must be kept > separate even if the representation is the same. You're essentially arguing > both sides of this argument at the same time. Not at all. I say that the choice depends on the problem space. Types are used to model things. When modeled things are unrelated so must be the types. When modeled things are related then types must be mixed. Representation is irrelevant it is a vehicle to achieve the goal, an implementation detail. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-17 9:36 ` Dmitry A. Kazakov 2013-03-18 23:13 ` Randy Brukardt @ 2013-03-19 0:38 ` Shark8 2013-03-19 8:53 ` Dmitry A. Kazakov 1 sibling, 1 reply; 242+ messages in thread From: Shark8 @ 2013-03-19 0:38 UTC (permalink / raw) Cc: mailbox On Sunday, March 17, 2013 3:36:19 AM UTC-6, Dmitry A. Kazakov wrote: > On Sat, 16 Mar 2013 14:51:58 -0700 (PDT), Shark8 wrote: > > > I think it's rather a shame that the compile-time computation aspect of > > generics is not emphasized a bit more > > You need no generics in order to compute something statically. Yes Ada > could be much better with an ability to declare a function static or > conditionally static. You misunderstand me; I wasn't saying that generics were required for compile-time computation, but that their use in compile-time computation is an interesting topic. (For example you could make a solar-system simulator by making 'orbit' a generic with the parameters cooresponding to Kepler's laws of motion.) ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-19 0:38 ` Shark8 @ 2013-03-19 8:53 ` Dmitry A. Kazakov 0 siblings, 0 replies; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-19 8:53 UTC (permalink / raw) On Mon, 18 Mar 2013 17:38:34 -0700 (PDT), Shark8 wrote: > On Sunday, March 17, 2013 3:36:19 AM UTC-6, Dmitry A. Kazakov wrote: >> On Sat, 16 Mar 2013 14:51:58 -0700 (PDT), Shark8 wrote: >> >>> I think it's rather a shame that the compile-time computation aspect of >>> generics is not emphasized a bit more >> >> You need no generics in order to compute something statically. Yes Ada >> could be much better with an ability to declare a function static or >> conditionally static. > > You misunderstand me; I wasn't saying that generics were required for > compile-time computation, but that their use in compile-time computation > is an interesting topic. Surely it is, especially for static checks/constraints defined by the user as it would be necessary for dimensioned arithmetic, matrix calculus etc. > (For example you could make a solar-system > simulator by making 'orbit' a generic with the parameters cooresponding to > Kepler's laws of motion.) Again, you don't need generics that. If you want "laws" be parameter bundle them into an interface. Generics/templates/preprocessor have no other purpose than to cover work around deficiencies of the language type system, premature optimization, lack of abstraction means. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-16 5:52 ` Shark8 2013-03-16 7:41 ` Dmitry A. Kazakov @ 2013-03-16 20:45 ` Robert A Duff 1 sibling, 0 replies; 242+ messages in thread From: Robert A Duff @ 2013-03-16 20:45 UTC (permalink / raw) Shark8 <onewingedshark@gmail.com> writes: > On Friday, March 15, 2013 3:46:26 PM UTC-6, Robert A Duff wrote: >> Many languages allow the type of an object to be deduced from >> its initial value. I believe C++ recently added that feature, >> using the "auto" keyword (which it inherited from C, and meant >> something completely different -- and completely useless). >> Ada allows that in a small way -- named numbers. > > This isn't _quite_ the same, it's declaring an object to be of the > same type as some other (and already known) object. Right, I didn't mean to imply it's the same. It's related. >> I suspect the reason was that the designers of Ada 83 thought that >> types of things ought to be explicit. Except for named numbers -- >> consistency wasn't their strong suit. > > I thought that named numbers were of the Universal_Integer (if > integral) or Universal_Float_and_Fixed if not... of course that could > just be an incorrect notion I've developed. That's correct. My point was that named numbers are an example where the type comes from the initial value. If you say "X : constant := Integer'Last;", X is of type universal_integer because the initial value is of some integer type -- the type of X is deduced from the type of its initial value. - Bob ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-15 21:46 ` Robert A Duff 2013-03-16 5:52 ` Shark8 @ 2013-03-16 9:29 ` Georg Bauhaus 2013-03-16 20:49 ` Robert A Duff 1 sibling, 1 reply; 242+ messages in thread From: Georg Bauhaus @ 2013-03-16 9:29 UTC (permalink / raw) On 15.03.13 22:46, Robert A Duff wrote: > That works in C because all sizes > are known at compile time. That's true in C89, but C99 makes sizeof an execution time operator for variable length arrays. The operand is then evaluated. 6.5.3.4 has this example, #include <stddef.h> size_t fsize3(int n) { char b[n+3]; // variable length array return sizeof b; // execution time sizeof } ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-16 9:29 ` Georg Bauhaus @ 2013-03-16 20:49 ` Robert A Duff 0 siblings, 0 replies; 242+ messages in thread From: Robert A Duff @ 2013-03-16 20:49 UTC (permalink / raw) Georg Bauhaus <rm.dash-bauhaus@futureapps.de> writes: > On 15.03.13 22:46, Robert A Duff wrote: >> That works in C because all sizes >> are known at compile time. > > That's true in C89, but C99 makes sizeof an execution > time operator for variable length arrays. Ah, yes. Thanks for the reminder. >...The operand > is then evaluated. Right. It seems confusing to me that the operand of sizeof is evaluated in some cases but not others. In Ada, the prefix of 'Size is always evaluated. My suggestion that the prefix of 'Type could be unevaluated (always) could work for the same reason sizeof can work like it does in C89. - Bob ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-13 17:45 ` Simon Wright 2013-03-13 19:37 ` Dmitry A. Kazakov @ 2013-03-14 22:41 ` Florian Weimer 1 sibling, 0 replies; 242+ messages in thread From: Florian Weimer @ 2013-03-14 22:41 UTC (permalink / raw) * Simon Wright: > I don't remember ever using 'Pred/'Succ, but I'd sorely miss > 'First/'Last. Personally, I find it rather odd that array bounds are preserved by slicing. This feature doesn't come for free, and leads to slightly more verbose code without conveying useful information. On the other hand, it makes array indexing effectively zero-based, which I find more natural. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-12 17:42 ` Dmitry A. Kazakov 2013-03-12 18:04 ` Georg Bauhaus @ 2013-03-12 23:21 ` Randy Brukardt 1 sibling, 0 replies; 242+ messages in thread From: Randy Brukardt @ 2013-03-12 23:21 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:8klywqh2pf$.1f949flc1xeia.dlg@40tude.net... > On Tue, 12 Mar 2013 13:19:06 -0400, Robert A Duff wrote: ... >>> for I in Prime'Range loop -- What is this supposed to mean? >>> ... >> >> It doesn't mean anything -- it's illegal. > > Why Prime'Succ is legal then? You could argue that it should have been. But as it is an operation on a type, not a subtype, constraints and predicates aren't involved, so it doesn't need to be illegal. > And what about: > > for I in Prime'First..Prime'Last loop 'First and 'Last are also illegal on subtypes that have predicates. (See 3.2.4(26/3)). I argued that this is wrong, in that these are also operations returning values of the base type. The above means: for I in Prime'Base range Prime'First .. Prime'Last loop and that is quite meaningful. But there was concern over confusing this with for I in Prime loop which clearly involves the subtype. Making 'First and 'Last illegal also ties in with the impossibility of having an array indexed by a subtype with a predicate (which is nearly impossible to implement, especially because of the possibility of slices). That had to be illegal and the related features were carried along. Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-12 9:27 ` Dmitry A. Kazakov 2013-03-12 17:19 ` Robert A Duff @ 2013-03-12 23:14 ` Randy Brukardt 1 sibling, 0 replies; 242+ messages in thread From: Randy Brukardt @ 2013-03-12 23:14 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message news:mtz6eyrgv524.r2yf3jw9vid3$.dlg@40tude.net... > On Mon, 11 Mar 2013 13:41:43 -0700 (PDT), Shark8 wrote: > > [...] >> We don't want the subtype "Head" to fail when the Pred'(Pos) is applied >> [and Pos = 1] while declaring the range; this precisely because the >> null-range is valid and what we desire. The construction of range 1..0 >> should therefore not generate an exception despite 0 not being a member >> of >> Positive. > > The issue of the bounds of an empty string is not related to subtypes. It > has a long history. But in short, you should not break one thing in order > to save another. I totally agree. You should build a time-machine in order to go back and tell Jean Ichbiah and his team that. But until you do, it is very relevant for Ada - because that is the decision that they made and we're stuck with it forever (including all weird consequences). Randy. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-11 20:01 ` Robert A Duff 2013-03-11 20:41 ` Shark8 @ 2013-03-11 20:43 ` Anh Vo 2013-03-11 22:32 ` Randy Brukardt 2013-03-11 22:38 ` Robert A Duff 2013-03-12 9:17 ` Dmitry A. Kazakov 2 siblings, 2 replies; 242+ messages in thread From: Anh Vo @ 2013-03-11 20:43 UTC (permalink / raw) On Monday, March 11, 2013 1:01:04 PM UTC-7, Robert A Duff wrote: >> Anh Vo <anhvofrcaus@gmail.com> writes: >> I have read ARM section 3.2.4, Subtype Predicates, I did not see any >> rules prohibiting from using attribute 'Succ as contained in the code >> nipet below. I would expect Prime'Succ (3) return 5 for next prime >> number. However, 4 is returned instead. Is this a correct behavior? >It is standard-conforming behavior. Prime'Succ is the same as Prime'Base'Succ. >Many other attributes behave the same way. This has been true since Ada 83. >For example, Prime'Succ(1000) = 1001, and does not raise an exception. >Positive'Image (-10) = "-10". Thank you for your clarification. My next question is that should ARM mention some thing of that effect regarding subtype predicates. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-11 20:43 ` Anh Vo @ 2013-03-11 22:32 ` Randy Brukardt 2013-03-11 22:38 ` Robert A Duff 1 sibling, 0 replies; 242+ messages in thread From: Randy Brukardt @ 2013-03-11 22:32 UTC (permalink / raw) "Anh Vo" <anhvofrcaus@gmail.com> wrote in message news:ec2783d9-1ae6-419e-97ad-12cb9e6c3d74@googlegroups.com... >On Monday, March 11, 2013 1:01:04 PM UTC-7, Robert A Duff wrote: >>> Anh Vo <anhvofrcaus@gmail.com> writes: >>> I have read ARM section 3.2.4, Subtype Predicates, I did not see any >>> rules prohibiting from using attribute 'Succ as contained in the code >>> nipet below. I would expect Prime'Succ (3) return 5 for next prime >>> number. However, 4 is returned instead. Is this a correct behavior? > >>It is standard-conforming behavior. Prime'Succ is the same as >>Prime'Base'Succ. >>Many other attributes behave the same way. This has been true since Ada >>83. >>For example, Prime'Succ(1000) = 1001, and does not raise an exception. >>Positive'Image (-10) = "-10". > >Thank you for your clarification. My next question is that should ARM >mention >some thing of that effect regarding subtype predicates. It seems unnecessary, because the behavior is the same as that for constraints. Usually, we only talk specifically about predicates when their behavior is different than constraints -- otherwise we'd be repeating dozens of "obvious" notes. And of course the Standard is not a tutorial for the language. One could argue that 'Pred and 'Succ should have been illegal (like 'First and 'Last are), but it's too late to do that. The reason that 'First and 'Last are illegal is because of potential confusion about the meaning. The same is true here - but the effect is less (it's the same as constraints), so its a marginal case in any event. Randy. P.S. I'm surprised anyone uses those attributes: I almost never do. Now, if we had implemented the procedure version that we talked about briefly, that would have gotten plenty of use. ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-11 20:43 ` Anh Vo 2013-03-11 22:32 ` Randy Brukardt @ 2013-03-11 22:38 ` Robert A Duff 1 sibling, 0 replies; 242+ messages in thread From: Robert A Duff @ 2013-03-11 22:38 UTC (permalink / raw) (Sorry, I didn't mean to send email.) Anh Vo <anhvofrcaus@gmail.com> writes: > Thank you for your clarification. You're welcome. >...My next question is that should ARM > mention some thing of that effect regarding subtype predicates. It's not necessary. The description of S'Succ makes it clear that it applies to S'Base, and returns S'Base. And it says somewhere that the predicate of a base subtype is True. And that the values of a subtype don't care about predicates anyway. Potentially confusing, perhaps, but I think it's correct. Now an Ada textbook, on the other hand ... - Bob ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-11 20:01 ` Robert A Duff 2013-03-11 20:41 ` Shark8 2013-03-11 20:43 ` Anh Vo @ 2013-03-12 9:17 ` Dmitry A. Kazakov 2013-03-13 0:10 ` Shark8 2 siblings, 1 reply; 242+ messages in thread From: Dmitry A. Kazakov @ 2013-03-12 9:17 UTC (permalink / raw) On Mon, 11 Mar 2013 16:01:04 -0400, Robert A Duff wrote: > Anh Vo <anhvofrcaus@gmail.com> writes: > >> I have read ARM section 3.2.4, Subtype Predicates, I did not see any >> rules prohibiting from using attribute 'Succ as contained in the code >> nipet below. I would expect Prime'Succ (3) return 5 for next prime >> number. However, 4 is returned instead. Is this a correct behavior? > > It is standard-conforming behavior. Prime'Succ is the same as > Prime'Base'Succ. Is the profile same? Let S be a subtype of T, then is 'Succ contravariant in the result? E.g. function "'Succ" (X : S) return T'Base; for any subtype. Or it is just an erroneous inheritance of the base operation for fully covariant function "'Succ" (X : S) return S; Or, maybe, it is not even covariant in the argument. Which might be the case. Considering Prime'Succ (2) If 'Succ is convariant in the argument, this shall raise Constraint_Error because 2 is not Prime. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 242+ messages in thread
* Re: Is this expected behavior or not 2013-03-12 9:17 ` Dmitry A. Kazakov @ 2013-03-13 0:10 ` Shark8 0 siblings, 0 replies; 242+ messages in thread From: Shark8 @ 2013-03-13 0:10 UTC (permalink / raw) Cc: mailbox On Tuesday, March 12, 2013 3:17:37 AM UTC-6, Dmitry A. Kazakov wrote: > > If 'Succ is convariant in the argument, this shall raise Constraint_Error > because 2 is not Prime. And here I thought it was prime, in fact I would have made the claim that it is the only element of the set of even prime numbers. ^ permalink raw reply [flat|nested] 242+ messages in thread
end of thread, other threads:[~2013-04-20 6:39 UTC | newest] Thread overview: 242+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2013-03-11 19:42 Is this expected behavior or not Anh Vo 2013-03-11 20:01 ` Robert A Duff 2013-03-11 20:41 ` Shark8 2013-03-12 9:27 ` Dmitry A. Kazakov 2013-03-12 17:19 ` Robert A Duff 2013-03-12 17:42 ` Dmitry A. Kazakov 2013-03-12 18:04 ` Georg Bauhaus 2013-03-12 18:21 ` Dmitry A. Kazakov 2013-03-12 22:23 ` Georg Bauhaus 2013-03-13 8:49 ` Dmitry A. Kazakov 2013-03-13 9:45 ` J-P. Rosen 2013-03-13 13:31 ` Dmitry A. Kazakov 2013-03-13 14:34 ` Georg Bauhaus 2013-03-13 15:51 ` Dmitry A. Kazakov 2013-03-13 16:56 ` Jeffrey Carter 2013-03-13 17:09 ` Shark8 2013-03-13 17:32 ` Georg Bauhaus 2013-03-13 19:28 ` Dmitry A. Kazakov 2013-03-13 21:01 ` Randy Brukardt 2013-03-13 21:18 ` Dmitry A. Kazakov 2013-03-14 21:51 ` Randy Brukardt 2013-03-15 1:10 ` Adam Beneschan 2013-03-15 21:22 ` Randy Brukardt 2013-03-15 9:20 ` Dmitry A. Kazakov 2013-03-15 21:43 ` Randy Brukardt 2013-03-16 7:56 ` Dmitry A. Kazakov 2013-03-18 22:52 ` Randy Brukardt 2013-03-19 10:32 ` Dmitry A. Kazakov 2013-03-13 21:37 ` Georg Bauhaus 2013-03-14 11:18 ` Dmitry A. Kazakov 2013-03-14 12:37 ` Georg Bauhaus 2013-03-14 14:26 ` Dmitry A. Kazakov 2013-03-14 14:57 ` Georg Bauhaus 2013-03-14 15:51 ` Anh Vo 2013-03-14 16:21 ` J-P. Rosen 2013-03-14 17:29 ` Dmitry A. Kazakov 2013-03-14 18:16 ` Georg Bauhaus 2013-03-15 9:33 ` Dmitry A. Kazakov 2013-03-15 10:05 ` Georg Bauhaus 2013-03-15 11:15 ` Dmitry A. Kazakov 2013-03-14 22:12 ` Randy Brukardt 2013-03-15 9:46 ` Dmitry A. Kazakov [not found] ` <ewe0v3ck1xdo$.e8rtuof27ke6$.dlg@40tude.net > 2013-03-15 21:17 ` Randy Brukardt 2013-03-16 7:51 ` Dmitry A. Kazakov 2013-03-16 9:30 ` Georg Bauhaus 2013-03-16 10:27 ` Dmitry A. Kazakov 2013-03-16 11:37 ` Georg Bauhaus 2013-03-16 13:04 ` Dmitry A. Kazakov 2013-03-16 16:10 ` Georg Bauhaus 2013-03-16 17:47 ` Dmitry A. Kazakov 2013-03-18 22:36 ` Randy Brukardt 2013-03-19 10:14 ` Dmitry A. Kazakov 2013-03-19 14:23 ` Georg Bauhaus 2013-03-19 15:13 ` Dmitry A. Kazakov 2013-03-19 16:52 ` Georg Bauhaus 2013-03-19 17:31 ` Dmitry A. Kazakov 2013-03-19 20:07 ` J-P. Rosen 2013-03-19 20:45 ` Dmitry A. Kazakov 2013-03-19 21:59 ` J-P. Rosen 2013-03-20 10:04 ` Dmitry A. Kazakov 2013-03-20 11:01 ` J-P. Rosen 2013-03-20 13:21 ` Dmitry A. Kazakov 2013-03-20 23:31 ` Randy Brukardt 2013-03-21 9:08 ` Dmitry A. Kazakov 2013-03-22 10:23 ` J-P. Rosen 2013-03-22 14:54 ` Dmitry A. Kazakov 2013-03-22 22:18 ` J-P. Rosen 2013-03-22 23:05 ` Shark8 2013-03-23 8:32 ` Dmitry A. Kazakov 2013-03-23 8:14 ` Dmitry A. Kazakov 2013-03-23 9:02 ` J-P. Rosen 2013-03-23 10:19 ` Dmitry A. Kazakov 2013-03-23 21:53 ` J-P. Rosen 2013-03-24 8:17 ` Dmitry A. Kazakov 2013-03-24 8:27 ` J-P. Rosen 2013-03-24 13:01 ` AdaMagica 2013-03-25 8:32 ` Dmitry A. Kazakov 2013-03-25 9:19 ` Georg Bauhaus 2013-03-25 10:08 ` Dmitry A. Kazakov 2013-03-19 21:37 ` Randy Brukardt 2013-03-20 8:48 ` Dmitry A. Kazakov 2013-03-14 16:22 ` Shark8 2013-03-14 17:08 ` Dmitry A. Kazakov 2013-03-13 22:34 ` Robert A Duff 2013-03-14 9:09 ` Dmitry A. Kazakov 2013-03-14 9:27 ` Georg Bauhaus 2013-03-13 17:05 ` Shark8 2013-03-13 17:45 ` Simon Wright 2013-03-13 19:37 ` Dmitry A. Kazakov 2013-03-13 19:54 ` Simon Wright 2013-03-13 20:54 ` Dmitry A. Kazakov 2013-03-13 21:28 ` Simon Wright 2013-03-14 9:16 ` Dmitry A. Kazakov 2013-03-14 16:42 ` Simon Wright 2013-03-14 17:05 ` Dmitry A. Kazakov 2013-03-13 22:12 ` Robert A Duff 2013-03-13 21:47 ` Jeffrey Carter 2013-03-13 21:09 ` Randy Brukardt 2013-03-13 22:48 ` Shark8 2013-03-14 22:01 ` Randy Brukardt 2013-03-15 3:27 ` Shark8 2013-03-15 21:05 ` Randy Brukardt 2013-03-15 21:46 ` Robert A Duff 2013-03-16 5:52 ` Shark8 2013-03-16 7:41 ` Dmitry A. Kazakov 2013-03-16 16:55 ` Shark8 2013-03-16 17:36 ` Dmitry A. Kazakov 2013-03-16 21:51 ` Shark8 2013-03-17 9:36 ` Dmitry A. Kazakov 2013-03-18 23:13 ` Randy Brukardt 2013-03-19 9:12 ` Dmitry A. Kazakov 2013-03-19 21:19 ` Randy Brukardt 2013-03-20 11:21 ` Dmitry A. Kazakov 2013-03-20 23:57 ` Randy Brukardt 2013-03-21 10:30 ` Dmitry A. Kazakov 2013-03-21 23:27 ` Randy Brukardt 2013-03-22 16:07 ` Dmitry A. Kazakov 2013-03-22 20:10 ` Shark8 2013-03-22 20:51 ` Dmitry A. Kazakov 2013-03-22 23:34 ` Robert A Duff 2013-03-23 8:41 ` Dmitry A. Kazakov 2013-03-23 2:29 ` Nasser M. Abbasi 2013-03-23 2:33 ` Randy Brukardt 2013-03-23 4:44 ` Shark8 2013-03-25 22:24 ` Randy Brukardt 2013-03-26 1:15 ` Shark8 2013-03-23 9:53 ` Dmitry A. Kazakov 2013-03-25 22:58 ` Randy Brukardt 2013-03-26 10:52 ` Dmitry A. Kazakov 2013-03-26 21:31 ` Randy Brukardt 2013-03-27 9:37 ` Dmitry A. Kazakov 2013-03-27 19:42 ` Randy Brukardt 2013-03-28 13:50 ` Dmitry A. Kazakov 2013-03-28 21:55 ` Randy Brukardt 2013-03-29 12:26 ` Dmitry A. Kazakov 2013-03-30 0:49 ` Randy Brukardt 2013-03-30 2:55 ` Shark8 2013-04-01 23:43 ` Messaging question [was: Is this expected behavior or not] Randy Brukardt 2013-03-30 9:20 ` Is this expected behavior or not Dmitry A. Kazakov 2013-04-02 0:40 ` Randy Brukardt 2013-04-02 8:44 ` Dmitry A. Kazakov 2013-04-02 21:54 ` Randy Brukardt 2013-04-03 8:54 ` Dmitry A. Kazakov 2013-04-04 0:04 ` Randy Brukardt 2013-04-04 8:26 ` Dmitry A. Kazakov 2013-04-04 20:31 ` Randy Brukardt 2013-04-05 9:57 ` Dmitry A. Kazakov 2013-04-05 12:45 ` Stefan.Lucks 2013-04-05 12:49 ` Stefan.Lucks 2013-04-05 14:19 ` Dmitry A. Kazakov 2013-04-05 14:44 ` Stefan.Lucks 2013-04-05 16:11 ` Dmitry A. Kazakov 2013-04-05 19:02 ` Stefan.Lucks 2013-04-05 19:34 ` Dmitry A. Kazakov 2013-04-05 20:23 ` Stefan.Lucks 2013-04-06 7:39 ` Dmitry A. Kazakov 2013-04-07 18:10 ` Stefan.Lucks 2013-04-07 18:23 ` Dmitry A. Kazakov 2013-04-05 20:38 ` Stefan.Lucks 2013-04-05 14:36 ` Dmitry A. Kazakov 2013-04-05 15:16 ` Stefan.Lucks 2013-04-05 16:29 ` Dmitry A. Kazakov 2013-04-05 19:55 ` Stefan.Lucks 2013-04-06 1:45 ` Randy Brukardt 2013-04-06 7:54 ` Dmitry A. Kazakov 2013-04-07 18:17 ` Stefan.Lucks 2013-04-07 18:28 ` Dmitry A. Kazakov 2013-04-08 7:48 ` Stefan.Lucks 2013-04-08 8:59 ` Dmitry A. Kazakov 2013-04-08 15:35 ` Stefan.Lucks 2013-04-08 19:08 ` Dmitry A. Kazakov 2013-04-09 7:18 ` Stefan.Lucks 2013-04-09 8:17 ` Dmitry A. Kazakov 2013-04-09 15:20 ` Stefan.Lucks 2013-04-09 16:15 ` Dmitry A. Kazakov 2013-04-09 22:59 ` Randy Brukardt 2013-04-09 22:57 ` Randy Brukardt 2013-04-10 7:30 ` Dmitry A. Kazakov 2013-04-10 8:00 ` Root_String'Class? (Was: Is this expected behavior or not) Jacob Sparre Andersen 2013-04-10 21:48 ` Randy Brukardt 2013-04-09 22:53 ` Is this expected behavior or not Randy Brukardt 2013-04-09 22:45 ` Randy Brukardt 2013-04-10 7:37 ` Dmitry A. Kazakov 2013-04-10 22:15 ` Randy Brukardt 2013-04-11 7:33 ` Dmitry A. Kazakov 2013-04-11 22:37 ` Randy Brukardt 2013-04-12 7:47 ` Dmitry A. Kazakov 2013-04-13 0:26 ` Randy Brukardt 2013-04-13 0:35 ` Randy Brukardt 2013-04-13 7:07 ` Dmitry A. Kazakov 2013-04-06 1:38 ` Randy Brukardt 2013-04-06 1:20 ` Randy Brukardt 2013-04-06 5:20 ` Usefulness of OOP (was Is this expected behavior or not) J-P. Rosen 2013-04-06 10:31 ` Dmitry A. Kazakov 2013-04-06 18:43 ` Georg Bauhaus 2013-04-07 7:00 ` Is this expected behavior or not Dmitry A. Kazakov 2013-04-09 23:24 ` Randy Brukardt 2013-04-10 8:20 ` Dmitry A. Kazakov 2013-04-10 22:07 ` Randy Brukardt 2013-04-11 7:59 ` Dmitry A. Kazakov 2013-04-11 11:10 ` Georg Bauhaus 2013-04-11 13:49 ` J-P. Rosen 2013-04-11 15:07 ` Dmitry A. Kazakov 2013-04-12 4:39 ` J-P. Rosen 2013-04-12 8:00 ` Dmitry A. Kazakov 2013-04-12 9:09 ` J-P. Rosen 2013-04-12 17:00 ` Jeffrey Carter 2013-04-11 23:02 ` Randy Brukardt 2013-04-12 8:17 ` Dmitry A. Kazakov 2013-04-12 9:41 ` Georg Bauhaus 2013-04-12 11:46 ` Dmitry A. Kazakov 2013-04-13 17:38 ` Georg Bauhaus 2013-04-13 0:22 ` Randy Brukardt 2013-04-13 6:49 ` Dmitry A. Kazakov 2013-04-16 1:41 ` Randy Brukardt 2013-04-16 8:03 ` Dmitry A. Kazakov 2013-04-16 22:57 ` Randy Brukardt 2013-04-17 7:18 ` Dmitry A. Kazakov 2013-04-17 9:23 ` Georg Bauhaus 2013-04-17 9:57 ` Dmitry A. Kazakov 2013-04-17 19:38 ` Georg Bauhaus 2013-04-18 11:52 ` Dmitry A. Kazakov 2013-04-19 2:16 ` Randy Brukardt 2013-04-19 7:39 ` Dmitry A. Kazakov 2013-04-19 9:07 ` Georg Bauhaus 2013-04-19 9:11 ` Georg Bauhaus 2013-04-19 12:09 ` Dmitry A. Kazakov 2013-04-19 22:14 ` Randy Brukardt 2013-04-20 6:39 ` Dmitry A. Kazakov 2013-03-19 0:38 ` Shark8 2013-03-19 8:53 ` Dmitry A. Kazakov 2013-03-16 20:45 ` Robert A Duff 2013-03-16 9:29 ` Georg Bauhaus 2013-03-16 20:49 ` Robert A Duff 2013-03-14 22:41 ` Florian Weimer 2013-03-12 23:21 ` Randy Brukardt 2013-03-12 23:14 ` Randy Brukardt 2013-03-11 20:43 ` Anh Vo 2013-03-11 22:32 ` Randy Brukardt 2013-03-11 22:38 ` Robert A Duff 2013-03-12 9:17 ` Dmitry A. Kazakov 2013-03-13 0:10 ` Shark8
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox