* limited types (Was: Records that could be arrays)
@ 2006-02-24 16:51 Thierry Bernier
2006-02-24 21:57 ` Randy Brukardt
0 siblings, 1 reply; 26+ messages in thread
From: Thierry Bernier @ 2006-02-24 16:51 UTC (permalink / raw)
Stephen Leake <stephe_on_the_web@toadmail.com> wrote :
> If we implemented points as limited private types, we wouldn't be
Please do not.
limited is like the flu : a record containing a limited field must be
limited itself.
For example, you can not extend a Gtk.Window.Gtk_Window_Type with an
extension containing a limited type, or else the root of these types must
be limited (and I don't own it).
limited should be used only when the type is really limited (when using
accesses, tasks, etc).
Disagrees ?
--
Thierry Bernier
^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: limited types (Was: Records that could be arrays) 2006-02-24 16:51 limited types (Was: Records that could be arrays) Thierry Bernier @ 2006-02-24 21:57 ` Randy Brukardt 2006-02-25 2:21 ` Matthew Heaney 2006-02-25 11:06 ` Dmitry A. Kazakov 0 siblings, 2 replies; 26+ messages in thread From: Randy Brukardt @ 2006-02-24 21:57 UTC (permalink / raw) "Thierry Bernier" <email@enon.moc> wrote in message news:Xns9774B59B784EFemailenonmoc@212.27.42.197... > Stephen Leake <stephe_on_the_web@toadmail.com> wrote : > > > If we implemented points as limited private types, we wouldn't be > > Please do not.limited is like the flu : a record containing a limited field must be > limited itself. > For example, you can not extend a Gtk.Window.Gtk_Window_Type with an > extension containing a limited type, or else the root of these types must > be limited (and I don't own it). > > limited should be used only when the type is really limited (when using > accesses, tasks, etc). > > Disagrees ? Limited is a flu, as you put it, but it is a pretty mild flu. Indeed, in Ada 200Y, it pretty much means that you can't assign it, and that's it. You can have aggregates and functions with suitable limitations. Indeed, many of us think that "limited" should be the default for Ada. (It certainly ought to be for interfaces and tagged types, because that allows more uses.) Only if you *need* assignment should something be non-limited. For example, your window example *should* be limited; it doesn't make sense to assign windows. (Yes, Claw does this wrong, too, mainly because of the limitations on the use of limited in Ada 95 that no longer apply.) That's especially valuable because then the extensions can include any kind of component. Of course, you often do need assignment. The containers are non-limited so that they can be composed. And that's because it doesn't make sense to have limited elements (as the elements have to be copied into the container). But in any case this is decision that needs to be made based on the use of the type, not for philosophical reasons... Randy. ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: limited types (Was: Records that could be arrays) 2006-02-24 21:57 ` Randy Brukardt @ 2006-02-25 2:21 ` Matthew Heaney 2006-02-25 3:38 ` Matthew Heaney 2006-02-25 11:06 ` Dmitry A. Kazakov 1 sibling, 1 reply; 26+ messages in thread From: Matthew Heaney @ 2006-02-25 2:21 UTC (permalink / raw) "Randy Brukardt" <randy@rrsoftware.com> writes: > Of course, you often do need assignment. The containers are non-limited so > that they can be composed. And that's because it doesn't make sense to have > limited elements (as the elements have to be copied into the container). On that subject, we recently had need of a bounded list (for restricted runtimes, sans dynamic memory allocation), something like: generic type ET is private; with "=" (L, R : ET) return Boolean is <>; package Ada.Containers.Bounded_Lists is type List (Capacity : Count_Type) is tagged limited private; ... -- more or less same as Doubly_Linked_Lists end; That brings up the composability issue, since you'd like to be able to create a container whose elements are bounded lists. I came up with something like: generic type ET is limited private; package Ada.Containers.Limited_Bounded_Lists is type List (Capacity : Count_Type) is tagged limited private; function Element (Container : not null access List; Position : Cursor) return not null access ET; function Constant_Element (Container : not null access constant List; Position : Cursor) return not null access constant ET; function First_Element (Container : not null access List) return not null access ET; function Constant_First_Element (Container : not null access constant List) return not null access constant ET; ... end; Query_Element and Update_Element are still there, but it's awfully nice to be able to rename an element directly. You can do something like: procedure Op (L : in out List) is begin L.Append (Initialize'Access); -- init elem -- or: L.Append; -- no init necessary -- or: L.Insert (Before => No_Element, Process => Initialize'Access); -- or: L.Insert (Before => No_Element); declare E : ET renames L.Last_Element; -- implicit 'Access begin ... -- use E end; end Op; The only potential issue is that if you rename an active element, it can subsequently become inactive (if you Delete it) in the scope of the renaming. If you were to subsequently manipulate it that would probably be bad, but at least the object doesn't disappear as it would in the unbounded case, since the object just moves onto an internal free list owned by the list. Don't know if that's the right thing to do, though. I haven't done anything with it yet so maybe I'll just get rid of those ops. It's just that in the case of a limited element, it's OK to declare the element as aliased, since there's no issue (I think) about constraining an element object whose type is a discriminated record with default discriminant. It was nice to be able to bounce ideas off of the ARG subcommittee. We ought to set up a mailing list or something to discuss post-Ada 2005 container issues. We might be able to reuse the old mailing list at yahoo if it's still around. -Matt ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: limited types (Was: Records that could be arrays) 2006-02-25 2:21 ` Matthew Heaney @ 2006-02-25 3:38 ` Matthew Heaney 0 siblings, 0 replies; 26+ messages in thread From: Matthew Heaney @ 2006-02-25 3:38 UTC (permalink / raw) Matthew Heaney <matthewjheaney@earthlink.net> writes: > declare > E : ET renames L.Last_Element; -- implicit 'Access ^^^^^^^^^^^^^^ Oops! Should be: E : ET renames L.Last_Element.all; ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: limited types (Was: Records that could be arrays) 2006-02-24 21:57 ` Randy Brukardt 2006-02-25 2:21 ` Matthew Heaney @ 2006-02-25 11:06 ` Dmitry A. Kazakov 2006-02-25 15:05 ` Matthew Heaney 1 sibling, 1 reply; 26+ messages in thread From: Dmitry A. Kazakov @ 2006-02-25 11:06 UTC (permalink / raw) On Fri, 24 Feb 2006 15:57:46 -0600, Randy Brukardt wrote: > Indeed, many of us think that "limited" should be the default for Ada. (It > certainly ought to be for interfaces and tagged types, because that allows > more uses.) Only if you *need* assignment should something be non-limited. Right > Of course, you often do need assignment. The containers are non-limited so > that they can be composed. And that's because it doesn't make sense to have > limited elements (as the elements have to be copied into the container). I think that there should also be [limited] containers of limited types. For this we need a construction model, which would allow user-defined in-place constructors. After all Ada has always had arrays of limited components. We have to extend this model onto user-defined containers. I think that this would require separation of assignment from copy constructor, as C++ does. Though the default must be that assignment is generated from destructor and copy constructor. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: limited types (Was: Records that could be arrays) 2006-02-25 11:06 ` Dmitry A. Kazakov @ 2006-02-25 15:05 ` Matthew Heaney 2006-02-26 1:01 ` Randy Brukardt 2006-02-26 9:00 ` Dmitry A. Kazakov 0 siblings, 2 replies; 26+ messages in thread From: Matthew Heaney @ 2006-02-25 15:05 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > I think that there should also be [limited] containers of limited types. > For this we need a construction model, which would allow user-defined > in-place constructors. After all Ada has always had arrays of limited > components. We have to extend this model onto user-defined containers. But you can pass in an Initialize procedure as a parameter of an insertion operation, to perform whatever initialization needs to be done. Also (see below for ex), you already have copy ctors for Ada 2005, even for limited types. > I think that this would require separation of assignment from copy > constructor, as C++ does. Though the default must be that assignment is > generated from destructor and copy constructor. You could pass in a copy constructor if this were an unbounded form (I thik), something like: procedure Insert (C : in out CT; E : in ET; Copy : not null access function (E : ET) return ET) is Node : Node_Access := new Node_Type'(Element => Copy (E), others => <>); begin ... end; Wouldn't that work? I don't have a compiler that can do that yet, but I know this would be legal: procedure Op (E : ET) is EE : ET := Copy (E); begin ... end; so I assume initialization of an aggregate is the same. (But I could be wrong.) ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: limited types (Was: Records that could be arrays) 2006-02-25 15:05 ` Matthew Heaney @ 2006-02-26 1:01 ` Randy Brukardt 2006-02-26 9:00 ` Dmitry A. Kazakov 1 sibling, 0 replies; 26+ messages in thread From: Randy Brukardt @ 2006-02-26 1:01 UTC (permalink / raw) "Matthew Heaney" <matthewjheaney@earthlink.net> wrote in message news:ufym7tr6w.fsf@earthlink.net... ... > You could pass in a copy constructor if this were an unbounded form (I thik), > something like: > > procedure Insert > (C : in out CT; > E : in ET; > Copy : not null access function (E : ET) return ET) > is > Node : Node_Access := > new Node_Type'(Element => Copy (E), others => <>); > begin > ... > end; > > Wouldn't that work? I don't have a compiler that can do that yet, but I know > this would be legal: Yes, that's legal (a limited function can be an aggregate element, and an aggregate can be used to initial an object). The compiler is required to build the object in place for such aggregates and functions; no temporaries are allowed. Randy. ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: limited types (Was: Records that could be arrays) 2006-02-25 15:05 ` Matthew Heaney 2006-02-26 1:01 ` Randy Brukardt @ 2006-02-26 9:00 ` Dmitry A. Kazakov 2006-02-26 18:20 ` Matthew Heaney 1 sibling, 1 reply; 26+ messages in thread From: Dmitry A. Kazakov @ 2006-02-26 9:00 UTC (permalink / raw) On Sat, 25 Feb 2006 15:05:02 GMT, Matthew Heaney wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > >> I think that there should also be [limited] containers of limited types. >> For this we need a construction model, which would allow user-defined >> in-place constructors. After all Ada has always had arrays of limited >> components. We have to extend this model onto user-defined containers. > > But you can pass in an Initialize procedure as a parameter of an insertion > operation, to perform whatever initialization needs to be done. You mean "return .. do" for limited types. It is in-place, but a constructing function does not have safety of a constructor. Then you cannot ask it from the type, so it can't have a default [deduced from the type.] It is not dispatching in Insert. What about container of class-wides, i.e. when Node_Type should have ET'Class? ... and of course passing pointers to functions is ugly. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: limited types (Was: Records that could be arrays) 2006-02-26 9:00 ` Dmitry A. Kazakov @ 2006-02-26 18:20 ` Matthew Heaney 2006-02-26 20:52 ` Dmitry A. Kazakov 0 siblings, 1 reply; 26+ messages in thread From: Matthew Heaney @ 2006-02-26 18:20 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > On Sat, 25 Feb 2006 15:05:02 GMT, Matthew Heaney wrote: > > > But you can pass in an Initialize procedure as a parameter of an insertion > > operation, to perform whatever initialization needs to be done. > > You mean "return .. do" for limited types. For an unbounded form, you could do it either way, via an Initialize procedure, or via a Copy function (using the new return do syntax). For a bounded form, only an Initialize procedure would work, since the actual initialization of the elements happens only once, when the (bounded) container object is elaborated. > It is in-place, but a constructing function does not have safety of a > constructor. Huh? An Ada 2005 constructor function *is* a constructor. It's no different from a copy ctor in C++. > Then you cannot ask it from the type, so it can't have a default > [deduced from the type.]. It is not dispatching in Insert. Aren't constructors always non-dispatching (unless you're using a Factory Method pattern)? But this is no different from the C++ STL. If you have an container (of indefinite elements) instantiated with (limited) type T'Class, then I suppose you might want to have a dispatching constructor. I'd have to think about how to do that[but see below]. (In my earlier example I was really thinking of bounded forms, which cannot have indefinite elements.) > What about container of class-wides, i.e. when Node_Type should have > ET'Class? Only applies to unbounded containers whose elements are indefinite. GCC allocates each indefinite element (so Node_Type has a pointer to ET). In general there's never any direct dispatching inside a generic, since the generic formal region doesn't pass in any operations, the formal type isn't tagged, and formal operations must be statically bound to the element type. If you wanted a contructor to dispatch, you'd have to say (assuming my knowledge of Ada 2005 is correct): type ET is tagged limited private; function Copy (E : ET) return ET; -- primitive op function Copy_Classwide (E : ET'Class) return ET'Class is begin return Copy (E); -- legal Ada 2005? end; Then you pass this in as per the example of my earlier post: package List_Types is new Limited_Indefinite_Lists (ET'Class); ... procedure Op (L : in out List) is begin ... L.Insert (...New_Item => E, Copy => Copy_Classwide...); ... end; Then the primitive Copy operation will dispatch according to the tag of actual parameter E. This is always what you do inside a generic to enable dispatching (when the generic formal type is non-tagged and indefinite). > ... and of course passing pointers to functions is ugly. This is not an argument. The existing API already has function pointers everywhere, so you might as well get used to it. ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: limited types (Was: Records that could be arrays) 2006-02-26 18:20 ` Matthew Heaney @ 2006-02-26 20:52 ` Dmitry A. Kazakov 2006-02-26 22:07 ` Matthew Heaney 0 siblings, 1 reply; 26+ messages in thread From: Dmitry A. Kazakov @ 2006-02-26 20:52 UTC (permalink / raw) On Sun, 26 Feb 2006 18:20:39 GMT, Matthew Heaney wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > >> It is in-place, but a constructing function does not have safety of a >> constructor. > > Huh? An Ada 2005 constructor function *is* a constructor. It's no different > from a copy ctor in C++. No. The constructor is wrapped by the function. Differently to a true constructor, you cannot ensure the wrapper to be always called for some specified signature. > If you have an container (of indefinite elements) instantiated with (limited) > type T'Class, then I suppose you might want to have a dispatching constructor. > I'd have to think about how to do that[but see below]. (In my earlier example > I was really thinking of bounded forms, which cannot have indefinite elements.) Consider the following use cases: 1. Containers of class-wide types (this will be possible.) 2. Subtypes of (1) constrained to a definite type from the class. 3. Containers of specific types building a parallel types hierarchy. I.e. if S is a subtype of T, then a container type with the elements of S is a subtype of a container type with the elements of T. >> What about container of class-wides, i.e. when Node_Type should have >> ET'Class? > > Only applies to unbounded containers whose elements are indefinite. GCC > allocates each indefinite element (so Node_Type has a pointer to ET). > > In general there's never any direct dispatching inside a generic, since the > generic formal region doesn't pass in any operations, the formal type isn't > tagged, and formal operations must be statically bound to the element type. > > If you wanted a contructor to dispatch, you'd have to say (assuming my > knowledge of Ada 2005 is correct): > > type ET is tagged limited private; > function Copy (E : ET) return ET; -- primitive op This you have to override in each of non-abstract derived type. If the compiler knew that Copy is a constructor it could safely compose it out of constructors of the bases and the components (in most of cases.) > function Copy_Classwide (E : ET'Class) return ET'Class is > begin > return Copy (E); -- legal Ada 2005? > end; I don't see why it should be illegal. But I wish the compiler to do this automatically. >> ... and of course passing pointers to functions is ugly. > > This is not an argument. The existing API already has function pointers > everywhere, so you might as well get used to it. And this is an argument? (:-)) Even if the functions were passed without pointers (as they should be in a language like Ada), even then it would be ugly, because the compiler and the reader of the code already have full information about what's going on. The type itself tells everything unambiguously. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: limited types (Was: Records that could be arrays) 2006-02-26 20:52 ` Dmitry A. Kazakov @ 2006-02-26 22:07 ` Matthew Heaney 2006-02-27 9:11 ` Dmitry A. Kazakov 0 siblings, 1 reply; 26+ messages in thread From: Matthew Heaney @ 2006-02-26 22:07 UTC (permalink / raw) "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > On Sun, 26 Feb 2006 18:20:39 GMT, Matthew Heaney wrote: > > Huh? An Ada 2005 constructor function *is* a constructor. It's no > > different from a copy ctor in C++. > > No. The constructor is wrapped by the function. Differently to a true > constructor, you cannot ensure the wrapper will always be called for some > specified signature. This is a specious argument. If you says the "real" constructor is wrapped by a function then you're guilty of moving the goal-posts. We're talking about requiring that a constructor be called. The syntax doesn't matter. That fact that Ada 2005 spells it f-u-n-c-t-i-o-n is irrelevent. If you want to force a constructor to be used, then you can make the partial view of the type indefinite. > Consider the following use cases: > > 1. Containers of class-wide types (this will be possible.) Yes, you already have this. > 3. Containers of specific types building a parallel types hierarchy. I.e. > if S is a subtype of T, then a container type with the elements of S is a > subtype of a container type with the elements of T. You have totally misunderstood the design of the Ada 2005 container library. When you use cursors, then this abstracts-away the container itself, leaving you with a sequence of elements. This model works for all the containers already (and for arrays too, in fact). Write your algorithms in terms of sequences of elements instead of containers, and you can forget about containers. > > type ET is tagged limited private; > > function Copy (E : ET) return ET; -- primitive op > > This you have to override in each of non-abstract derived type. Not quite. You have to override only if this is a non-null extension. But again that's no different from C++. Derived classes need to implement their own ctor, if only to call the ctor of the base class. (In the typical case, the base class is abstract, and its ctor is declared as protected. The ctor available to users is the ctor of the derived class.) > If the compiler knew that Copy is a constructor it could safely compose it > out of constructors of the bases and the components (in most of cases.) In practice concrete derived classes must implement their own ctors, that call the ctor of the base class. > > function Copy_Classwide (E : ET'Class) return ET'Class is > > begin > > return Copy (E); -- legal Ada 2005? > > end; > > I don't see why it should be illegal. But I wish the compiler to do this > automatically. But I did this to show you how call a dispatching operation inside a generic, with a non-tagged indefinite formal type. It's completely consistent with the existing generic model. When are operations for generic formal private types ever just synthesized? In the case at hand, you need an operation that takes type ET'Class, which is the type used to instantiate the generic, so you have to write it yourself, the same as for any other operation. > And this is an argument? (:-)) This ignores the history of Ada language evolution: Ada83: no function pointers; royal pain Ada95: function pointers at library-level only: GUI callbacks, etc Ada05: function pointers in nested scopes too No one seems to agree with you, Dmitry! The trend has been to allow the declaration of "ugly" function pointers in more places, not fewer. ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: limited types (Was: Records that could be arrays) 2006-02-26 22:07 ` Matthew Heaney @ 2006-02-27 9:11 ` Dmitry A. Kazakov 2006-02-27 14:34 ` Georg Bauhaus 0 siblings, 1 reply; 26+ messages in thread From: Dmitry A. Kazakov @ 2006-02-27 9:11 UTC (permalink / raw) On Sun, 26 Feb 2006 22:07:00 GMT, Matthew Heaney wrote: > "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> writes: > >> On Sun, 26 Feb 2006 18:20:39 GMT, Matthew Heaney wrote: >>> Huh? An Ada 2005 constructor function *is* a constructor. It's no >>> different from a copy ctor in C++. >> >> No. The constructor is wrapped by the function. Differently to a true >> constructor, you cannot ensure the wrapper will always be called for some >> specified signature. > > This is a specious argument. If you says the "real" constructor is wrapped by > a function then you're guilty of moving the goal-posts. > > We're talking about requiring that a constructor be called. The syntax doesn't > matter. That fact that Ada 2005 spells it f-u-n-c-t-i-o-n is irrelevent. There is a fundamental difference between a subprogram and a constructor. A subprogram can implement a part of a constructor (like Initialize), it can call to a constructor (like Copy), but it cannot *be* a constructor. Constructors are not decomposable into subprograms. Copy is a subprogram as any other. That means, other subprograms can do exactly the same, i.e. you have a backdoor wide open. > If you want to force a constructor to be used, then you can make the partial > view of the type indefinite. It is not a programmer's choice and not a question of view. There should be absolutely no way to pass construction by. >> 3. Containers of specific types building a parallel types hierarchy. I.e. >> if S is a subtype of T, then a container type with the elements of S is a >> subtype of a container type with the elements of T. > > You have totally misunderstood the design of the Ada 2005 container library. > > When you use cursors, then this abstracts-away the container itself, leaving > you with a sequence of elements. This model works for all the containers > already (and for arrays too, in fact). > > Write your algorithms in terms of sequences of elements instead of containers, > and you can forget about containers. No, thanks. If I wished that sort of untyped design, there would be C++ and dynamically typed languages at my disposal. I don't want untyped containers. I would keep boxes for apples and barrels for herrings in separate rooms. >> If the compiler knew that Copy is a constructor it could safely compose it >> out of constructors of the bases and the components (in most of cases.) > > In practice concrete derived classes must implement their own ctors, that call > the ctor of the base class. It must be called automatically, like in C++. It is already so in Ada for the parts generated by the compiler. You cannot override construction of the components. There is no reason to treat user-defined parts otherwise. You can skip Initialize, when you inherit and cannot when you aggregating. Nonsense. > In the case at hand, you need an operation that takes type ET'Class, which is > the type used to instantiate the generic, so you have to write it yourself, the > same as for any other operation. This is an untyped model. As I said, I prefer a contract-based model. If copyable type is the contract, that should require a copy constructor. >> And this is an argument? (:-)) > > This ignores the history of Ada language evolution: > > Ada83: no function pointers; royal pain > Ada95: function pointers at library-level only: GUI callbacks, etc > Ada05: function pointers in nested scopes too > > No one seems to agree with you, Dmitry! The trend has been to allow the > declaration of "ugly" function pointers in more places, not fewer. When Ada 95 added function pointers, it just admitted that functions are regular objects. When Ada 05 allows anonymous access types for functions it only pursues this idea of regularity further. I see no reason how this can contradict to functions as values? Why a function cannot be passed as a normal "in" parameter of limited type? Give me a reason. Why don't we write: "not null access Integer" to pass Integer? Further, considering distributed systems, how to marshal a function to remote node, if functions does not have values? -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: limited types (Was: Records that could be arrays) 2006-02-27 9:11 ` Dmitry A. Kazakov @ 2006-02-27 14:34 ` Georg Bauhaus 2006-02-27 16:05 ` Dmitry A. Kazakov 0 siblings, 1 reply; 26+ messages in thread From: Georg Bauhaus @ 2006-02-27 14:34 UTC (permalink / raw) Dmitry A. Kazakov wrote: > On Sun, 26 Feb 2006 22:07:00 GMT, Matthew Heaney wrote: >> Write your algorithms in terms of sequences of elements instead of containers, >> and you can forget about containers. > > No, thanks. If I wished that sort of untyped design, there would be C++ and > dynamically typed languages at my disposal. I don't want untyped > containers. I would keep boxes for apples and barrels for herrings in > separate rooms. What kind of operations on containers do you have in mind, as opposed to operations focussing on their elements? -- Georg ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: limited types (Was: Records that could be arrays) 2006-02-27 14:34 ` Georg Bauhaus @ 2006-02-27 16:05 ` Dmitry A. Kazakov 2006-02-27 16:52 ` Matthew Heaney 0 siblings, 1 reply; 26+ messages in thread From: Dmitry A. Kazakov @ 2006-02-27 16:05 UTC (permalink / raw) On Mon, 27 Feb 2006 15:34:58 +0100, Georg Bauhaus wrote: > Dmitry A. Kazakov wrote: >> On Sun, 26 Feb 2006 22:07:00 GMT, Matthew Heaney wrote: > >>> Write your algorithms in terms of sequences of elements instead of containers, >>> and you can forget about containers. >> >> No, thanks. If I wished that sort of untyped design, there would be C++ and >> dynamically typed languages at my disposal. I don't want untyped >> containers. I would keep boxes for apples and barrels for herrings in >> separate rooms. > > What kind of operations on containers do you have in mind, > as opposed to operations focussing on their elements? 1. Passing as a parameter 2. Copying 3. Merging 4. Slicing 5. Closures and simultaneous traversal of two or more containers 6. Relational operations on sets of containers ... -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: limited types (Was: Records that could be arrays) 2006-02-27 16:05 ` Dmitry A. Kazakov @ 2006-02-27 16:52 ` Matthew Heaney 2006-02-27 20:21 ` Dmitry A. Kazakov 0 siblings, 1 reply; 26+ messages in thread From: Matthew Heaney @ 2006-02-27 16:52 UTC (permalink / raw) Dmitry A. Kazakov wrote: > > 1. Passing as a parameter Just pass a cursor: procedure Op (C : in out Container_Type) is begin Do_Something (C.First); ... end; You know you've run out of elements when Has_Element returns False. > 2. Copying while (Has_Element (C) loop Put_Element_Somewhere (Element (C); end loop; > 3. Merging You'll need to define a relational operator over your element type, but then you can say: Merge (C1.First, C2.First); > 4. Slicing Just use a cursor pair: Do_Something (C1, C2); -- half-open range > 5. Closures and simultaneous traversal of two or more containers Do_Something (C1, C2); > 6. Relational operations on sets of containers Compare (C1, C2); If you don't understand this, go to http://charles.tigris.org and browse the Charles.Algorithms subsystem. (Things are a little different for the Ada 2005 container library, but it should give you the general idea.) ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: limited types (Was: Records that could be arrays) 2006-02-27 16:52 ` Matthew Heaney @ 2006-02-27 20:21 ` Dmitry A. Kazakov 2006-02-27 21:40 ` Georg Bauhaus 2006-02-27 23:00 ` Matthew Heaney 0 siblings, 2 replies; 26+ messages in thread From: Dmitry A. Kazakov @ 2006-02-27 20:21 UTC (permalink / raw) On 27 Feb 2006 08:52:23 -0800, Matthew Heaney wrote: > Dmitry A. Kazakov wrote: >> >> 1. Passing as a parameter > > Just pass a cursor: I don't see how a constraint imposed on elements can propagate to the cursor. The question Georg asked was: where typed containers of elements of related types might themselves appear related. The number of cases is huge. Generics fundamentally cannot help here, they aren't dynamically polymorphic. Whatever you do, the polymorphism can come only from outside, like in the case of a tagged formal parameter, or as a type inheritance in the declarative part of a generic package. So generics are completely irrelevant to the discussion about the design of constructors and the types system. >> 2. Copying > > while (Has_Element (C) loop > Put_Element_Somewhere (Element (C); > end loop; It is dynamic typing. The constraint check would happen at run-time. Too late. You just have tossed a stinking herring in a jug apple cider... >> 3. Merging > > You'll need to define a relational operator over your element type, but > then you can say: > > Merge (C1.First, C2.First); Same as above. I don't mix herrings and apples, because barrels and boxes never meet in the production line. But they can on a container ship. And their elements do in someone's stomach. >> 4. Slicing > > Just use a cursor pair: > > Do_Something (C1, C2); -- half-open range Huh, what about a submatrix? The main diagonal of? And, BTW, I don't do anything I want to get a new container. [...] > Do_Something (C1, C2); > Compare (C1, C2); Same as above. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: limited types (Was: Records that could be arrays) 2006-02-27 20:21 ` Dmitry A. Kazakov @ 2006-02-27 21:40 ` Georg Bauhaus 2006-02-28 9:38 ` Dmitry A. Kazakov 2006-02-27 23:00 ` Matthew Heaney 1 sibling, 1 reply; 26+ messages in thread From: Georg Bauhaus @ 2006-02-27 21:40 UTC (permalink / raw) Dmitry A. Kazakov wrote: > The question Georg asked was: where typed containers of elements of related > types might themselves appear related. The number of cases is huge. > Generics fundamentally cannot help here, they aren't dynamically > polymorphic. But then wouldn't you again be mixing apples and herrings? type APPLE_CONTAINER is new CONTAINER with null record; -- specializes in apples, only type HERRING_CONTAINER is new CONTAINER with null record; -- specializes in herrings, only x: access CONTAINER'class := ...; x.insert(an_apple); -- right or wrong? compile time? > It is dynamic typing. The constraint check would happen at run-time. Too > late. You just have tossed a stinking herring in a jug apple cider... > > >>>3. Merging >> >>You'll need to define a relational operator over your element type, but >>then you can say: >> >>Merge (C1.First, C2.First); > > > Same as above. I don't mix herrings and apples, In fact, herrings with little pieces of apple aren't that unusual, add onions and mayonnaise and you are almost set - not everyone's taste, maybe. :-) Seriously, wouldn't type-forcing containers be in the way of composition? How do you make a vector of doughnuts with different toppings? Something like zip(doughnuts.first, toppings.first); seems reasonable to me. ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: limited types (Was: Records that could be arrays) 2006-02-27 21:40 ` Georg Bauhaus @ 2006-02-28 9:38 ` Dmitry A. Kazakov 0 siblings, 0 replies; 26+ messages in thread From: Dmitry A. Kazakov @ 2006-02-28 9:38 UTC (permalink / raw) On Mon, 27 Feb 2006 22:40:18 +0100, Georg Bauhaus wrote: > Dmitry A. Kazakov wrote: > >> The question Georg asked was: where typed containers of elements of related >> types might themselves appear related. The number of cases is huge. >> Generics fundamentally cannot help here, they aren't dynamically >> polymorphic. > > But then wouldn't you again be mixing apples and herrings? > > type APPLE_CONTAINER is new CONTAINER with null record; > -- specializes in apples, only > > type HERRING_CONTAINER is new CONTAINER with null record; > -- specializes in herrings, only > > x: access CONTAINER'class := ...; > > x.insert(an_apple); -- right or wrong? compile time? You cannot tell without the contract of Container. The above could be compile error, run-time error or correct. There are three [all useful] variants: 1. Containers of related types are unrelated 2. Containers of related types are same 3. Containers of subtypes are subtypes (polymorphic containers) [there is also an axis for the container index/cursor types] The variants 1 and 2 are relatively easy to get. The variant 3 is much more challenging. Consider [imaginary syntax]: type Food is ... type Food_Container is ..; -- of Food'Class type Apple is new Food with ...; type Herring is new Food with ...; type Apple_Box is new Food_Container (Element'Tag => Apple'Class); type Herring_Barrel is new Food_Container (Element'Tag => Herring'Class); X : Food_Container'Class := Some_Herring_Barrel; Y : Herring_Barrel := Some_Herring_Barrel; X.Insert (An_Apple); -- Constraint_Error at run-time Y.Insert (An_Apple); -- Constraint_Error at run-time + compiler warning With full ADT one could also do this type Apple_Only_Box is new Food_Container some syntax sugar; private type Apple_Only_Box is array (...) of Apple; -- The implementation of the container is completely overridden -- and replaced by a more efficient > In fact, herrings with little pieces of apple aren't > that unusual, add onions and mayonnaise and you are > almost set - rather pickled red beets and cucumbers ... > not everyone's taste, maybe. :-) Not in a class of apple juice! (:-)) > Seriously, > wouldn't type-forcing containers be in the way of > composition? It will, when that is what's needed. It should be programmer's choice. And it is much more flexible that the choices we have now: either same type or different types. Ada was always better than that. Consider Integer and Positive as an example. Now what about an array of Integers vs. an array of Positives. Then a slice of an array of Positives. Presently, constraints cannot propagate between types. This is a weakness of the type system. You cannot get an array subtype by constraining its elements. You cannot get an access subtype by constraining the target type. This is more general and important question than just container types. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: limited types (Was: Records that could be arrays) 2006-02-27 20:21 ` Dmitry A. Kazakov 2006-02-27 21:40 ` Georg Bauhaus @ 2006-02-27 23:00 ` Matthew Heaney 2006-02-28 9:39 ` Dmitry A. Kazakov 1 sibling, 1 reply; 26+ messages in thread From: Matthew Heaney @ 2006-02-27 23:00 UTC (permalink / raw) Dmitry A. Kazakov wrote: > > I don't see how a constraint imposed on elements can propagate to the > cursor. generic type ET is private; type Cursor is private; with function E (C : Cursor) return ET is <>; ... procedure Generic_Algorithm (C1, C2 : CT); ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: limited types (Was: Records that could be arrays) 2006-02-27 23:00 ` Matthew Heaney @ 2006-02-28 9:39 ` Dmitry A. Kazakov 2006-02-28 17:24 ` Matthew Heaney 0 siblings, 1 reply; 26+ messages in thread From: Dmitry A. Kazakov @ 2006-02-28 9:39 UTC (permalink / raw) On 27 Feb 2006 15:00:29 -0800, Matthew Heaney wrote: > Dmitry A. Kazakov wrote: >> >> I don't see how a constraint imposed on elements can propagate to the >> cursor. > > generic > type ET is private; > type Cursor is private; > > with function E (C : Cursor) return ET is <>; > ... > procedure Generic_Algorithm (C1, C2 : CT); Instantiate Generic_Algorithm with some T and CT. Then put a constraint on T, that will be a subtype S or a derived type. Now how to get CS from CT? -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: limited types (Was: Records that could be arrays) 2006-02-28 9:39 ` Dmitry A. Kazakov @ 2006-02-28 17:24 ` Matthew Heaney 2006-02-28 19:06 ` Dmitry A. Kazakov 0 siblings, 1 reply; 26+ messages in thread From: Matthew Heaney @ 2006-02-28 17:24 UTC (permalink / raw) Dmitry A. Kazakov wrote: > > Instantiate Generic_Algorithm with some T and CT. Then put a constraint on > T, that will be a subtype S or a derived type. Now how to get CS from CT? Easy: instantiate Generic_Algorithm again, on type S. ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: limited types (Was: Records that could be arrays) 2006-02-28 17:24 ` Matthew Heaney @ 2006-02-28 19:06 ` Dmitry A. Kazakov 2006-02-28 19:58 ` Matthew Heaney 0 siblings, 1 reply; 26+ messages in thread From: Dmitry A. Kazakov @ 2006-02-28 19:06 UTC (permalink / raw) On 28 Feb 2006 09:24:35 -0800, Matthew Heaney wrote: > Dmitry A. Kazakov wrote: >> >> Instantiate Generic_Algorithm with some T and CT. Then put a constraint on >> T, that will be a subtype S or a derived type. Now how to get CS from CT? > > Easy: instantiate Generic_Algorithm again, on type S. I still don't see CS. BTW, if I had CS, would need not to instantiate Generic_Algorithm once more. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: limited types (Was: Records that could be arrays) 2006-02-28 19:06 ` Dmitry A. Kazakov @ 2006-02-28 19:58 ` Matthew Heaney 2006-02-28 21:03 ` Dmitry A. Kazakov 2006-02-28 21:51 ` limited types Simon Wright 0 siblings, 2 replies; 26+ messages in thread From: Matthew Heaney @ 2006-02-28 19:58 UTC (permalink / raw) Dmitry A. Kazakov wrote: > On 28 Feb 2006 09:24:35 -0800, Matthew Heaney wrote: > > I still don't see CS. I wrote the declaration wrong; it should have been: generic type ET is private; --or: type ET (<>) is limited private; type CT is private; --cursor type with function E (C : CT) return ET is <>; procedure Generic_Algorithm (C1, C2 : CT); The cursor pair [C1, C2) describes a range of elements. It might be the entire range of elements in the container, or just a subrange. The algorithm doesn't care. > BTW, if I had CS, would need not to instantiate Generic_Algorithm once > more. (I assume "CS" means "container of element type S, and S derives from type T.") As far as generic algorithms are concerned, it doesn't matter that type S derives from type T. That's what "generic algorithm" means. And yes, you have to instantiate the algorithm twice, since the cursor types come from different instantiations of some generic container package. Of course, if you instantiate the indefinite container package on generic actual type T'Class, then you'd only have to instantate generic algorithm once (assuming generic formal type ET is declared appropriately, as I show above in the comment). ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: limited types (Was: Records that could be arrays) 2006-02-28 19:58 ` Matthew Heaney @ 2006-02-28 21:03 ` Dmitry A. Kazakov 2006-02-28 21:51 ` limited types Simon Wright 1 sibling, 0 replies; 26+ messages in thread From: Dmitry A. Kazakov @ 2006-02-28 21:03 UTC (permalink / raw) On 28 Feb 2006 11:58:11 -0800, Matthew Heaney wrote: > Dmitry A. Kazakov wrote: >> On 28 Feb 2006 09:24:35 -0800, Matthew Heaney wrote: >> >> I still don't see CS. > > I wrote the declaration wrong; it should have been: > > generic > type ET is private; --or: type ET (<>) is limited private; > type CT is private; --cursor type > with function E (C : CT) return ET is <>; > procedure Generic_Algorithm (C1, C2 : CT); > > The cursor pair [C1, C2) describes a range of elements. It might be > the entire range of elements in the container, or just a subrange. The > algorithm doesn't care. But still S <: T does not imply CS <: CT. >> BTW, if I had CS, would need not to instantiate Generic_Algorithm once >> more. > > (I assume "CS" means "container of element type S, and S derives from > type T.") Yes and CS should be a subtype of CT, so that CS could be passed as an "in" where CT is expected. It also could be as an "out", but then with a chance of Constraint_Error at run-time. > As far as generic algorithms are concerned, it doesn't matter that type > S derives from type T. That's what "generic algorithm" means. It means "works on a set of types." Generics are only one [weakest] form of polymorphism. > And yes, you have to instantiate the algorithm twice, since the cursor > types come from different instantiations of some generic container > package. That is the whole point. BTW, you will need to instantiate it more than twice for cross combinations, like when C1 is CS and C2 is CT. It geometrically explodes. -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: limited types 2006-02-28 19:58 ` Matthew Heaney 2006-02-28 21:03 ` Dmitry A. Kazakov @ 2006-02-28 21:51 ` Simon Wright 2006-03-01 1:59 ` Matthew Heaney 1 sibling, 1 reply; 26+ messages in thread From: Simon Wright @ 2006-02-28 21:51 UTC (permalink / raw) "Matthew Heaney" <mheaney@on2.com> writes: > generic > type ET is private; --or: type ET (<>) is limited private; > type CT is private; --cursor type > with function E (C : CT) return ET is <>; > procedure Generic_Algorithm (C1, C2 : CT); > > The cursor pair [C1, C2) describes a range of elements. It might be > the entire range of elements in the container, or just a subrange. > The algorithm doesn't care. I would have expected some operation like Succ on CT? (and equality? would predefined equality on cursors be OK?) ^ permalink raw reply [flat|nested] 26+ messages in thread
* Re: limited types 2006-02-28 21:51 ` limited types Simon Wright @ 2006-03-01 1:59 ` Matthew Heaney 0 siblings, 0 replies; 26+ messages in thread From: Matthew Heaney @ 2006-03-01 1:59 UTC (permalink / raw) Simon Wright <simon@pushface.org> writes: > I would have expected some operation like Succ on CT? Yeah, you're right; I forgot to write an ellipsis. Each algorithm would have to pass in the requisite element/cursor operations as generic formals. For a similar idea, see Ada.Containers.Generic_Anonymous_Array_Sort in the GNAT distribution. > (and equality? would predefined equality on cursors be OK?) The standard container library guarantees that cursor equality composes, so predefined equality would work fine. It wouldn't hurt to pass in a default equality operator, though. ^ permalink raw reply [flat|nested] 26+ messages in thread
end of thread, other threads:[~2006-03-01 1:59 UTC | newest] Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2006-02-24 16:51 limited types (Was: Records that could be arrays) Thierry Bernier 2006-02-24 21:57 ` Randy Brukardt 2006-02-25 2:21 ` Matthew Heaney 2006-02-25 3:38 ` Matthew Heaney 2006-02-25 11:06 ` Dmitry A. Kazakov 2006-02-25 15:05 ` Matthew Heaney 2006-02-26 1:01 ` Randy Brukardt 2006-02-26 9:00 ` Dmitry A. Kazakov 2006-02-26 18:20 ` Matthew Heaney 2006-02-26 20:52 ` Dmitry A. Kazakov 2006-02-26 22:07 ` Matthew Heaney 2006-02-27 9:11 ` Dmitry A. Kazakov 2006-02-27 14:34 ` Georg Bauhaus 2006-02-27 16:05 ` Dmitry A. Kazakov 2006-02-27 16:52 ` Matthew Heaney 2006-02-27 20:21 ` Dmitry A. Kazakov 2006-02-27 21:40 ` Georg Bauhaus 2006-02-28 9:38 ` Dmitry A. Kazakov 2006-02-27 23:00 ` Matthew Heaney 2006-02-28 9:39 ` Dmitry A. Kazakov 2006-02-28 17:24 ` Matthew Heaney 2006-02-28 19:06 ` Dmitry A. Kazakov 2006-02-28 19:58 ` Matthew Heaney 2006-02-28 21:03 ` Dmitry A. Kazakov 2006-02-28 21:51 ` limited types Simon Wright 2006-03-01 1:59 ` Matthew Heaney
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox