* prohibit certain generic instantiations in Ada 2005 @ 2006-02-09 18:01 matteo.bordin 2006-02-09 20:02 ` Matthew Heaney 0 siblings, 1 reply; 17+ messages in thread From: matteo.bordin @ 2006-02-09 18:01 UTC (permalink / raw) There's a way to prohibit certain generic instantiations (I'm using Ada 2005)? For example: generic Type B is new A with private; ... Should be instantiated only with a certain subtype(s) of A. I know a way to do that in C++ (with templates) but it doesn't seem to work in Ada. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: prohibit certain generic instantiations in Ada 2005 2006-02-09 18:01 prohibit certain generic instantiations in Ada 2005 matteo.bordin @ 2006-02-09 20:02 ` Matthew Heaney 2006-02-10 14:18 ` matteo.bordin 0 siblings, 1 reply; 17+ messages in thread From: Matthew Heaney @ 2006-02-09 20:02 UTC (permalink / raw) The question is non-sensical. If you create a hierarchy rooted a type A, then that's basically a contract saying that all types in A'Class satisfy certain behavioral invariants. Viewed as an A, then all types in A'Class are the same. If you need to create an equivalence class among the types in A'Class, then you need to either perform another derivation (type B is new AA with private), or use interfaces. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: prohibit certain generic instantiations in Ada 2005 2006-02-09 20:02 ` Matthew Heaney @ 2006-02-10 14:18 ` matteo.bordin 2006-02-10 18:25 ` Dmitry A. Kazakov 0 siblings, 1 reply; 17+ messages in thread From: matteo.bordin @ 2006-02-10 14:18 UTC (permalink / raw) I understand and agree from a semantic point of view. However I would like to let the compiler perform some additional type checking on the generic instance. If the generic instantiation is not allowed, then I what the compiler to produce a compilation error. This makes sense if you are using generics as a generative tool for metaprogramming. This kind of things can be done in C++, which has a compilation model similar to Ada (for what concerns generics/templates). ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: prohibit certain generic instantiations in Ada 2005 2006-02-10 14:18 ` matteo.bordin @ 2006-02-10 18:25 ` Dmitry A. Kazakov 2006-02-10 19:03 ` Georg Bauhaus 2006-02-11 8:04 ` matteo.bordin 0 siblings, 2 replies; 17+ messages in thread From: Dmitry A. Kazakov @ 2006-02-10 18:25 UTC (permalink / raw) On 10 Feb 2006 06:18:30 -0800, matteo.bordin@gmail.com wrote: > I understand and agree from a semantic point of view. However I would > like to let the compiler perform some additional type checking on the > generic instance. If the generic instantiation is not allowed, then I > what the compiler to produce a compilation error. This makes sense if > you are using generics as a generative tool for metaprogramming. This > kind of things can be done in C++, which has a compilation model > similar to Ada (for what concerns generics/templates). I don't see how you came to this conclusion. C++ model is quite different, especially with respect of your question - it isn't contract based. So, basically, C++ is unable to check anything specific about the type of template a parameter. Ada's model is contract based, so types are fully checked. That in particular means, that there cannot be any "additional type" checking. Probably you meant something else. Note that the type contract can be strengthen in Ada by requiring some additional subroutines. For example: generic type S is new T with private; procedure Ad_Hoc (X : in out S) is <>; Here we require a type from T'Class plus some procedure Ad_Hoc defined on it. However, it is a *bad* practice from software design perspective inherited from Ada 83, which wasn't OO. A proper way is to make T'Class + Ad_Hoc explicit. If, for whatever reason, T is frozen, you should, as Matthew suggested, derive a new [maybe abstract] base: type T1 is abstract T with null record; procedure Ad_Hoc (X : in out T1) is abstract; -- This is a proper contract now generic type S is new T1 with private; -- Here we use the contract -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: prohibit certain generic instantiations in Ada 2005 2006-02-10 18:25 ` Dmitry A. Kazakov @ 2006-02-10 19:03 ` Georg Bauhaus 2006-02-11 10:45 ` Dmitry A. Kazakov 2006-02-11 8:04 ` matteo.bordin 1 sibling, 1 reply; 17+ messages in thread From: Georg Bauhaus @ 2006-02-10 19:03 UTC (permalink / raw) On Fri, 2006-02-10 at 19:25 +0100, Dmitry A. Kazakov wrote: > So, > basically, C++ is unable to check anything specific about the type of > template a parameter. Don't you think that while template <class T> doesn't require T to conform to some type, T's operations can still be named in the template definition? Like with the Can_Copy example that Stroustrup explains? >From this viewpoint I'd say that the compilation model of C++ is rather different, in that it defers some checks until much later, possibly involving the linker IIUC. -- Georg ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: prohibit certain generic instantiations in Ada 2005 2006-02-10 19:03 ` Georg Bauhaus @ 2006-02-11 10:45 ` Dmitry A. Kazakov 0 siblings, 0 replies; 17+ messages in thread From: Dmitry A. Kazakov @ 2006-02-11 10:45 UTC (permalink / raw) On Fri, 10 Feb 2006 20:03:25 +0100, Georg Bauhaus wrote: > On Fri, 2006-02-10 at 19:25 +0100, Dmitry A. Kazakov wrote: > >> So, >> basically, C++ is unable to check anything specific about the type of >> template a parameter. > > Don't you think that while template <class T> doesn't > require T to conform to some type, T's operations can > still be named in the template definition? Like with > the Can_Copy example that Stroustrup explains? Things from the definition are checked upon instantiation = too late. Talking about compile-time checks, we should separate compilation of templates and their instantiations. In my view, anything checked outside the formal part does not count, because it is *other* compile-time. [ Let you use a code management system and a template library is under that system. Then each time you ship a new version of the library, all the projects dependant on it should get a new version as well. Now, because templates aren't properly checked, you can't much rely on them until you try. In the end, you have an immense overhead in the developing cycle.] -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: prohibit certain generic instantiations in Ada 2005 2006-02-10 18:25 ` Dmitry A. Kazakov 2006-02-10 19:03 ` Georg Bauhaus @ 2006-02-11 8:04 ` matteo.bordin 2006-02-11 9:54 ` Martin Krischik ` (2 more replies) 1 sibling, 3 replies; 17+ messages in thread From: matteo.bordin @ 2006-02-11 8:04 UTC (permalink / raw) I will provide a proper example in C++. With this code I can prohibit instantiation of template My_Class with T=int. class Checker{ public: static void check(float){}; private: static void check(int){}; }; template <class T> class My_Class{ public: My_Class(){ T t; Checker::check(t); } }; int main(){ My_Class<int> mc = My_Class<int>(); //COMPILE TIME ERROR!!!! //The error comes from the fact that Checker::check(int) is private My_Class<float> mc2 = My_Class<float>(); //OK!!! }; When I said that the compilation model for template of Ada is similar to C++, I meant in regards to compile-time code generation (opposed to the model of Java generics). In both languages (Ada and C++), templates can be used as a generative environment. I just want to know f here is a way to reproduce the C++ code I provided in Ada (2005). Thank you ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: prohibit certain generic instantiations in Ada 2005 2006-02-11 8:04 ` matteo.bordin @ 2006-02-11 9:54 ` Martin Krischik 2006-02-11 10:20 ` matteo.bordin 2006-02-11 10:45 ` Dmitry A. Kazakov 2006-02-11 15:36 ` Stephen Leake 2 siblings, 1 reply; 17+ messages in thread From: Martin Krischik @ 2006-02-11 9:54 UTC (permalink / raw) matteo.bordin@gmail.com wrote: > I will provide a proper example in C++. With this code I can prohibit > instantiation of template My_Class with T=int. > > class Checker{ > public: > static void check(float){}; > private: > static void check(int){}; > }; > > template <class T> > class My_Class{ > public: > My_Class(){ > T t; > Checker::check(t); > > } > }; > > int main(){ > > My_Class<int> mc = My_Class<int>(); //COMPILE TIME ERROR!!!! > //The error comes from the fact that Checker::check(int) is private > My_Class<float> mc2 = My_Class<float>(); //OK!!! > }; Sorry, but that look like a hack to me. A hack to hack in a feature into a language which does not have that feature. > When I said that the compilation model for template of Ada is similar > to C++, I meant in regards to compile-time code generation (opposed to > the model of Java generics). In both languages (Ada and C++), templates > can be used as a generative environment. > I just want to know f here is a way to reproduce the C++ code I > provided in Ada (2005). The obvious solution would be: generic type T is digits <>; package My_Class end My_Class; Of course that is positive logic: Instead of disallowing integer I only allow floating point types. But that is the natural way in Ada: you declare which types are suitable for the template. I don't think you can compare C++ and Ada on that level. C++ only has user defined struct/union/class. And as such only struct/union/class play any important role in templates all other types are only 2nd class. Or can you any of those: template <int T[]> class My_Class{}; template <float T> class My_Class{}; typedef double f(double x); template <f* T> class My_Class{}; Yes you could do then all with the aid of a helper class. But that would only proof my point: For templates struct/union/class in 1st class all other only 2nd class after thoughts. And you initial example needed a helper class as well. Ada on the other had has user defined integer, floats, decimals, arrays, functions and record (did I foreget one) and so you can specify any of those as parameter to a tempate. Ada supports all the examples above without a helper class or package: generic type Integer_Type is range <>; -- optional type Array_Type is array (Positive range <>) of Integer_Type; -- optional T : in Array_Type; package My_Class end My_Class; generic type Float_Type is digits <>; -- optional T : in Float_Type; package My_Class end My_Class; generic type Float_Type is digits <>; -- optional with function T (x : in Float_Type) return Float_Type; package My_Class end My_Class; As you see: an different concept alltogether. Martin -- mailto://krischik@users.sourceforge.net Ada programming at: http://ada.krischik.com ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: prohibit certain generic instantiations in Ada 2005 2006-02-11 9:54 ` Martin Krischik @ 2006-02-11 10:20 ` matteo.bordin 2006-02-11 12:46 ` Martin Krischik 0 siblings, 1 reply; 17+ messages in thread From: matteo.bordin @ 2006-02-11 10:20 UTC (permalink / raw) I used integer and float as an example. In reality, I want to discern on different interface implementation (as in the firsdt example I provided). ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: prohibit certain generic instantiations in Ada 2005 2006-02-11 10:20 ` matteo.bordin @ 2006-02-11 12:46 ` Martin Krischik 0 siblings, 0 replies; 17+ messages in thread From: Martin Krischik @ 2006-02-11 12:46 UTC (permalink / raw) matteo.bordin@gmail.com wrote: > I used integer and float as an example. In reality, I want to discern > on different interface implementation (as in the firsdt example I > provided). Something along that line: generic type Base_Object (<>) is abstract tagged limited private; package AdaCL.Reference.Mixin end AdaCL.Reference.Mixin; generic with package RefCounted is new AdaCL.Reference.Mixin (<>); type RefCounted_Object (<>) is abstract new RefCounted.Object with private; package AdaCL.Reference.Ptr end AdaCL.Reference.Ptr; If you want to know the rest of the packages you can just download AdaCL (http://adacl.sf). Martin -- mailto://krischik@users.sourceforge.net Ada programming at: http://ada.krischik.com ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: prohibit certain generic instantiations in Ada 2005 2006-02-11 8:04 ` matteo.bordin 2006-02-11 9:54 ` Martin Krischik @ 2006-02-11 10:45 ` Dmitry A. Kazakov 2006-02-11 22:20 ` Jeffrey R. Carter 2006-02-11 15:36 ` Stephen Leake 2 siblings, 1 reply; 17+ messages in thread From: Dmitry A. Kazakov @ 2006-02-11 10:45 UTC (permalink / raw) On 11 Feb 2006 00:04:44 -0800, matteo.bordin@gmail.com wrote: > I will provide a proper example in C++. With this code I can prohibit > instantiation of template My_Class with T=int. > > class Checker{ > public: > static void check(float){}; > private: > static void check(int){}; > }; > > template <class T> > class My_Class{ > public: > My_Class(){ > T t; > Checker::check(t); > > } > }; > > int main(){ > > My_Class<int> mc = My_Class<int>(); //COMPILE TIME ERROR!!!! > //The error comes from the fact that Checker::check(int) is private > My_Class<float> mc2 = My_Class<float>(); //OK!!! > }; Your example in Ada would be: generic type T is digits <>; -- Only floating-point is allowed T is specified by its contract: a floating-point type, rather than using ad-hoc matching. It isn't clear what you are going to achieve using the technique like in your example. What if T were long? The trick you mention should be impossible in legal Ada, because generics are compilable separately [thank to the contract model.] So if any error may occur, then only in the formal part. [GNAT Ada has a lot of problems with this, but these are just bugs.] In means that any trick should rely on the formal parameter part. For example: generic type T is private; with function "+" (Left : T) return Float is <>; This will reject Integer and accept Float. But, again, it is an awful style. Now to your example. It has a direct Ada equivalent (checks are moved to the formal part): package Checker is function Check (T : Float) return Float renames "+"; end Checker; with Checker; use Checker; generic type T is private; wth function Check (X : T) return T is <>; -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: prohibit certain generic instantiations in Ada 2005 2006-02-11 10:45 ` Dmitry A. Kazakov @ 2006-02-11 22:20 ` Jeffrey R. Carter 0 siblings, 0 replies; 17+ messages in thread From: Jeffrey R. Carter @ 2006-02-11 22:20 UTC (permalink / raw) Dmitry A. Kazakov wrote: > package Checker is > function Check (T : Float) return Float renames "+"; > end Checker; > > with Checker; use Checker; > generic > type T is private; > wth function Check (X : T) return T is <>; Actually, "is Checker.Check" is closer here to the OP's idea, but even then the user can supply another function for the Check. What the OP has posted is a template that can only be instantiated with float; that's no generic at all. -- Jeff Carter "Whatever it is, I'm against it." Horse Feathers 46 ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: prohibit certain generic instantiations in Ada 2005 2006-02-11 8:04 ` matteo.bordin 2006-02-11 9:54 ` Martin Krischik 2006-02-11 10:45 ` Dmitry A. Kazakov @ 2006-02-11 15:36 ` Stephen Leake 2006-02-12 8:55 ` matteo.bordin 2 siblings, 1 reply; 17+ messages in thread From: Stephen Leake @ 2006-02-11 15:36 UTC (permalink / raw) matteo.bordin@gmail.com writes: > I will provide a proper example in C++. With this code I can prohibit > instantiation of template My_Class with T=int. > > class Checker{ > public: > static void check(float){}; > private: > static void check(int){}; > }; > > template <class T> > class My_Class{ > public: > My_Class(){ > T t; > Checker::check(t); > > } > }; > > int main(){ > > My_Class<int> mc = My_Class<int>(); //COMPILE TIME ERROR!!!! > //The error comes from the fact that Checker::check(int) is private > My_Class<float> mc2 = My_Class<float>(); //OK!!! > }; > > When I said that the compilation model for template of Ada is similar > to C++, I meant in regards to compile-time code generation (opposed to > the model of Java generics). In both languages (Ada and C++), templates > can be used as a generative environment. Ok, you _can_ do this in C++. But they question remains; _why_ do you want to do this? What is it that Checker does that is appropriate for all types, except 'int'? > > just want to know f here is a way to reproduce the C++ code I > provided in Ada (2005). You can write code in the execution part of a package body (after the 'begin') that does some checking, and raises an exception. Most compilers will warn at compile time that a run-time construct will raise an exception. -- -- Stephe ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: prohibit certain generic instantiations in Ada 2005 2006-02-11 15:36 ` Stephen Leake @ 2006-02-12 8:55 ` matteo.bordin 2006-02-12 9:49 ` Dmitry A. Kazakov 2006-02-13 19:14 ` Matthew Heaney 0 siblings, 2 replies; 17+ messages in thread From: matteo.bordin @ 2006-02-12 8:55 UTC (permalink / raw) As I explained in a prewieus post, my int/float example was just didactic. I want that kind of checking because I want to use generics as a generative environment for a component-based approach. If I can map to the source code the knowledge that some template instantiations are not allowed, then I can let the compiler check for me if the user of the library I am writing is doing something wrong. For example, imagine I want to compose a car component with an Engine and a Transmission. Electric engine can be coupled only with automatic transmission, while gasoline engine can work with both automatic and manual transmission. Then the Car component is: generic type My_Engine is new Engine with private; type My_Transmission is new Transmission with private; package Car is .... Then I want to prohibit: package My_Car is new Car(My_Engine => Electric_Engine, My_Transmission => Manual_Tansmission). As you can see there is a reason to do that. And there is other reasons to want static (compile-time) checking insteam of run-time exceptions. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: prohibit certain generic instantiations in Ada 2005 2006-02-12 8:55 ` matteo.bordin @ 2006-02-12 9:49 ` Dmitry A. Kazakov 2006-02-12 12:41 ` matteo.bordin 2006-02-13 19:14 ` Matthew Heaney 1 sibling, 1 reply; 17+ messages in thread From: Dmitry A. Kazakov @ 2006-02-12 9:49 UTC (permalink / raw) On 12 Feb 2006 00:55:52 -0800, matteo.bordin@gmail.com wrote: > As I explained in a prewieus post, my int/float example was just > didactic. I want that kind of checking because I want to use generics > as a generative environment for a component-based approach. If I can > map to the source code the knowledge that some template instantiations > are not allowed, then I can let the compiler check for me if the user > of the library I am writing is doing something wrong. For example, > imagine I want to compose a car component with an Engine and a > Transmission. Electric engine can be coupled only with automatic > transmission, while gasoline engine can work with both automatic and > manual transmission. Then the Car component is: > > generic > type My_Engine is new Engine with private; > type My_Transmission is new Transmission with private; > package Car is > .... > > Then I want to prohibit: > > package My_Car is new Car(My_Engine => Electric_Engine, My_Transmission > => Manual_Tansmission). > > As you can see there is a reason to do that. And there is other reasons > to want static (compile-time) checking insteam of run-time exceptions. OK, but there must be something that requires automatic transmission for an electric engine. This something need to be factored out and specified in the contract. It is an OOA/D question. Consider an implementation of Engine. If My_Engine cannot be controlled by Manual_Transmission, then, say, procedure Switch (E : in out Engine; T : Transmission'Class); will raise run-time error. So the problem is not in Car, but between Engine and Transmission. It is not Car, which imposes constraints. OK, you can still do it in Car, if you want: generic type My_Engine is new Engine with private; type My_Transmission is new Transmission with private; with procedure Switch (E : in out My_Engine; T : My_Transmission) is <>; package Car is Now, if there is no Switch for Electric_Engine and Manual_Tansmission, Car will not be instantiated. However, I see it as a bad design, because the relationship between Engine and Transmission is not clearly specified. But even so, it is not obvious why Car need to be generic rather than mix-in: type Abstract_Car (E : access Engine'Class; T : access Transmission'Class) is ... More specialized cars could be defined using inheritance: type Abstract_Electric_Car (E : Electric_Engine'Class; T : Electric_Transmission'Class) is new Abstract_Car (E, T) with ... [my rule of thumb: avoid generics] -- Regards, Dmitry A. Kazakov http://www.dmitry-kazakov.de ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: prohibit certain generic instantiations in Ada 2005 2006-02-12 9:49 ` Dmitry A. Kazakov @ 2006-02-12 12:41 ` matteo.bordin 0 siblings, 0 replies; 17+ messages in thread From: matteo.bordin @ 2006-02-12 12:41 UTC (permalink / raw) I agree with you that the use of generics in my example is exagerated. But I am working on an application that requires a generic-based approach for components (while functional code can be "encapsulated" as classes' methods). BTW, the architecture I am working on has nothing to do with cars or transmission. As you said, the problem is more at the design/analysis level but it would be nice to map it on the code. The final aim is to produce a library that automatically checks at compile time if it is used correctly. ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: prohibit certain generic instantiations in Ada 2005 2006-02-12 8:55 ` matteo.bordin 2006-02-12 9:49 ` Dmitry A. Kazakov @ 2006-02-13 19:14 ` Matthew Heaney 1 sibling, 0 replies; 17+ messages in thread From: Matthew Heaney @ 2006-02-13 19:14 UTC (permalink / raw) Ada does have something called "signature packages" that are probably what you're looking for. The problem with your previous solutions is that you're trying to use types to solve your problem, instead of using generics to solve your problem (which was your original request). You want to be doing something like: generic type Engine is limited private; type Transmission is limited private; with procedure Attach (E : in out Engine; T : in out Transmission) is <>; with <other ops req'd by body go here> package Generic_Cars is ... end; Don't import generic formal tagged types if you don't need them. You only end up overcommitting yourself. Note that a limited private generic formal is a superset of tagged (limited), so you're still free to instantiate Generic_Cars with a tagged generic actual. You want to prevent attaching an electric engine to a manual transmission. That's fine. If no Attach for binding an electric engine to a manual transmission exists, then your problem is solved since you have no generic actual with which to instantiate the package. Stop trying to import tagged types. The only reason you'd need to do that is if the generic package itself needs to extend the formal type. Now that that's out of the way, I can get to what I mentioned at the top of my post. It's possible that the set of operations for engines and transmissions needed by the generic is large, and so the generic formal region becomes long since you must declare all the formal operations. To simplify things you can declare all the engine operations in a separate package (and do the same for the transmission in another package, if necessary), and then import an instantiation of the engine "signature" package as a generic formal, like this: generic type Engine (<>) is limited private; with procedure XXX (E : in out Engine) is <>; <lots of other engine ops here> package Generic_Engines is end; -- yes, spec is empty Now you can do this: generic type Engine is limited private; type Transmission is limited private; with Engines is new Generic_Engines (Engine, others => <>); -- verify my syntax with procedure Attach (E : in out Engine; ...) is <>; package Generic_Cars is ... end; That way you can instantiate the Generic_Engines package once for each interesting engine type (note again that you do NOT need a tagged type here), and then use that signature package as the generic actual. Stop using tagged types for everything. You want signature packages. ^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2006-02-13 19:14 UTC | newest] Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2006-02-09 18:01 prohibit certain generic instantiations in Ada 2005 matteo.bordin 2006-02-09 20:02 ` Matthew Heaney 2006-02-10 14:18 ` matteo.bordin 2006-02-10 18:25 ` Dmitry A. Kazakov 2006-02-10 19:03 ` Georg Bauhaus 2006-02-11 10:45 ` Dmitry A. Kazakov 2006-02-11 8:04 ` matteo.bordin 2006-02-11 9:54 ` Martin Krischik 2006-02-11 10:20 ` matteo.bordin 2006-02-11 12:46 ` Martin Krischik 2006-02-11 10:45 ` Dmitry A. Kazakov 2006-02-11 22:20 ` Jeffrey R. Carter 2006-02-11 15:36 ` Stephen Leake 2006-02-12 8:55 ` matteo.bordin 2006-02-12 9:49 ` Dmitry A. Kazakov 2006-02-12 12:41 ` matteo.bordin 2006-02-13 19:14 ` Matthew Heaney
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox