* How to define an array of a variant record type? @ 2003-11-17 16:57 Harald Schmidt 2003-11-17 17:35 ` Stephen Leake ` (4 more replies) 0 siblings, 5 replies; 12+ messages in thread From: Harald Schmidt @ 2003-11-17 16:57 UTC (permalink / raw) Hi, I would like to define an array, which its element type is a variant record and the Value_Type is only known at runtime. type Name_Value_Type is (String_Type, Integer_Type, Float_Type); type Name_Value(Value_Type : Name_Value_Type) is record The_Name : Unbounded_String; case Value_Type is when String_Type => String_Value : Unbounded_String; when Integer_Type => Integer_Value : Integer; when Float_Type => The_Value : Float; end case; end record; type Name_Value_Sequence is array(Natural range <>) of Name_Value; The compiler says "unconstrained element type in array declaration", ...right! I know Ada is a strong typed language, but sometimes information is only at runtime available. Does anyone know some workaround, or a regulare design pattern for this problem? Harald ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: How to define an array of a variant record type? 2003-11-17 16:57 How to define an array of a variant record type? Harald Schmidt @ 2003-11-17 17:35 ` Stephen Leake 2003-11-20 10:02 ` Craig Carey 2003-11-17 17:37 ` Marius Amado Alves ` (3 subsequent siblings) 4 siblings, 1 reply; 12+ messages in thread From: Stephen Leake @ 2003-11-17 17:35 UTC (permalink / raw) Harald Schmidt <office@anobject.net> writes: > type Name_Value_Type is (String_Type, > Integer_Type, > Float_Type); > > type Name_Value(Value_Type : Name_Value_Type) is change this to type Name_Value(Value_Type : Name_Value_Type := String_Type) is This seems very odd, but it works. It says to the compiler "let the discriminant change at runtime". Without the default value for the discriminant, the discriminant is _not_ allowed to change at runtime; it must be known at compile time. -- -- Stephe ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: How to define an array of a variant record type? 2003-11-17 17:35 ` Stephen Leake @ 2003-11-20 10:02 ` Craig Carey 0 siblings, 0 replies; 12+ messages in thread From: Craig Carey @ 2003-11-20 10:02 UTC (permalink / raw) On 17 Nov 2003 12:35:34 -0500, Stephen Leake wrote: ... >change this to > >type Name_Value(Value_Type : Name_Value_Type := String_Type) is > > >This seems very odd, but it works. It says to the compiler "let the >discriminant change at runtime". Without the default value for the >discriminant, the discriminant is _not_ allowed to change at runtime; >it must be known at compile time. http://www.adaic.org/standards/95aarm/html/AA-3-7.html AARM 3.7 Discriminants ... NOTES 28 50 If a discriminated type has default_expressions for its discriminants, then unconstrained variables of the type are permitted, and the values of the discriminants can be changed by an assignment to such a variable. If defaults are not provided for the discriminants, then all variables of the type are constrained, either by explicit constraint or by their initial value; the values of the discriminants of such a variable cannot be changed after initialization. 28.a Discussion: This connection between discriminant defaults and unconstrained variables can be a source of confusion. For Ada 95, we considered various ways to break the connection between defaults and unconstrainedness, but ultimately gave up for lack of a sufficiently simple and intuitive alternative. ... Presumably pesons could use Ada for 10 years without figuring that out, except for slow Leake of information at comp.lang.ada. ---- Also there is the pragma Volatile trick (that won't run in GNAT 3.15p due to the caching not going away): the discriminant is altered by using X'Address or similar, and pragma Volatile suppresses the caching. ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: How to define an array of a variant record type? 2003-11-17 16:57 How to define an array of a variant record type? Harald Schmidt 2003-11-17 17:35 ` Stephen Leake @ 2003-11-17 17:37 ` Marius Amado Alves 2003-11-18 2:48 ` Steve 2003-11-17 18:45 ` Rodrigo Garcia ` (2 subsequent siblings) 4 siblings, 1 reply; 12+ messages in thread From: Marius Amado Alves @ 2003-11-17 17:37 UTC (permalink / raw) To: comp.lang.ada To simulate arrays of indefinite or unconstrained elements in Ada you must use pointers (access types). Define an access type to your logical type, then define an array of such pointers. Your life will be slightly facilitated as Ada provides implicit dereference in most situations. ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: How to define an array of a variant record type? 2003-11-17 17:37 ` Marius Amado Alves @ 2003-11-18 2:48 ` Steve 2003-11-18 9:04 ` Marius Amado Alves 0 siblings, 1 reply; 12+ messages in thread From: Steve @ 2003-11-18 2:48 UTC (permalink / raw) "Marius Amado Alves" <amado.alves@netcabo.pt> wrote in message news:mailman.17.1069090659.3110.comp.lang.ada@ada-france.org... > To simulate arrays of indefinite or unconstrained elements in Ada you > must use pointers (access types). Define an access type to your logical > type, then define an array of such pointers. Your life will be slightly > facilitated as Ada provides implicit dereference in most situations. > Dynamic allocation is inherently more risky (having potential for memory leaks) than simply using a discriminated record with a default discriminant. Steve (The Duck) ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: How to define an array of a variant record type? 2003-11-18 2:48 ` Steve @ 2003-11-18 9:04 ` Marius Amado Alves 0 siblings, 0 replies; 12+ messages in thread From: Marius Amado Alves @ 2003-11-18 9:04 UTC (permalink / raw) To: comp.lang.ada On Tue, 2003-11-18 at 02:48, Steve wrote: > "Marius Amado Alves" <amado.alves@netcabo.pt> wrote: > > To simulate arrays of indefinite or unconstrained elements in Ada you > > must use pointers... > Dynamic allocation is inherently more risky (having potential for memory > leaks) than simply using a discriminated record with a default discriminant. You're right. Default discriminants is a better way for arrays of variant records. I had forgotten such types are definite (and can therefore be array components). ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: How to define an array of a variant record type? 2003-11-17 16:57 How to define an array of a variant record type? Harald Schmidt 2003-11-17 17:35 ` Stephen Leake 2003-11-17 17:37 ` Marius Amado Alves @ 2003-11-17 18:45 ` Rodrigo Garcia 2003-11-18 2:48 ` Steve 2003-11-18 17:48 ` Nick Roberts 4 siblings, 0 replies; 12+ messages in thread From: Rodrigo Garcia @ 2003-11-17 18:45 UTC (permalink / raw) "Harald Schmidt" <office@anobject.net> wrote in message news:BBDEBC6C.902D%office@anobject.net... > Hi, > > I would like to define an array, which its element type is a variant record > and the Value_Type is only known at runtime. > > type Name_Value_Type is (String_Type, > Integer_Type, > Float_Type); > > type Name_Value(Value_Type : Name_Value_Type) is > record > The_Name : Unbounded_String; > case Value_Type is > when String_Type => > String_Value : Unbounded_String; > when Integer_Type => > Integer_Value : Integer; > when Float_Type => > The_Value : Float; > end case; > end record; > > type Name_Value_Sequence is array(Natural range <>) of Name_Value; > > The compiler says "unconstrained element type in array declaration", > ...right! > > I know Ada is a strong typed language, but sometimes information is only at > runtime available. Does anyone know some workaround, or a regulare design > pattern for this problem? > > Harald I would use "Indirection": Use an array of _accesses_ to the variant record. type Name_Value_Ptr is access Name_Value; type Name_Value_Sequence is array (Natural range <>) of Name_Value_Ptr; Rodrigo ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: How to define an array of a variant record type? 2003-11-17 16:57 How to define an array of a variant record type? Harald Schmidt ` (2 preceding siblings ...) 2003-11-17 18:45 ` Rodrigo Garcia @ 2003-11-18 2:48 ` Steve 2003-11-18 17:48 ` Nick Roberts 4 siblings, 0 replies; 12+ messages in thread From: Steve @ 2003-11-18 2:48 UTC (permalink / raw) To do this you must use a "default discriminant". In your record type definition use: type Name_Value( Value_Type : Name_Value_Type := String_Type ) is ... There are a couple of other things you should be aware of. 1. When assigning values to the record, you can only change the type by doing a complete record assignment. That is: Value : Name_Value; Value := ( Value_Type => String_Type, --this is ok String_Value => To_Unbounded_String( "Hello" ); Value.Value_Type := Integer_Type; -- will not work Value := ( Value_Type => Integer_Type, -- ok Integer_Value => 42 ); Value.Integer_Value := 43; -- ok 2. You can only change the discriminant through the record assignment if the record was declared using the default. That is: Value : Name_Value(Integer_Type); Value := ( Value_Type => String_Type, -- will not work. String_Value => To_Unbounded_String( "Hello" ); Steve (The Duck) "Harald Schmidt" <office@anobject.net> wrote in message news:BBDEBC6C.902D%office@anobject.net... > Hi, > > I would like to define an array, which its element type is a variant record > and the Value_Type is only known at runtime. > > type Name_Value_Type is (String_Type, > Integer_Type, > Float_Type); > > type Name_Value(Value_Type : Name_Value_Type) is > record > The_Name : Unbounded_String; > case Value_Type is > when String_Type => > String_Value : Unbounded_String; > when Integer_Type => > Integer_Value : Integer; > when Float_Type => > The_Value : Float; > end case; > end record; > > type Name_Value_Sequence is array(Natural range <>) of Name_Value; > > The compiler says "unconstrained element type in array declaration", > ...right! > > I know Ada is a strong typed language, but sometimes information is only at > runtime available. Does anyone know some workaround, or a regulare design > pattern for this problem? > > Harald > > > ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: How to define an array of a variant record type? 2003-11-17 16:57 How to define an array of a variant record type? Harald Schmidt ` (3 preceding siblings ...) 2003-11-18 2:48 ` Steve @ 2003-11-18 17:48 ` Nick Roberts 2003-11-19 2:38 ` Steve 2003-11-19 13:26 ` Rodrigo Garcia 4 siblings, 2 replies; 12+ messages in thread From: Nick Roberts @ 2003-11-18 17:48 UTC (permalink / raw) Harald Schmidt wrote: > I would like to define an array, which its element type is a variant record > and the Value_Type is only known at runtime. > > type Name_Value_Type is (String_Type, > Integer_Type, > Float_Type); > > type Name_Value(Value_Type : Name_Value_Type) is > record > The_Name : Unbounded_String; > case Value_Type is > when String_Type => > String_Value : Unbounded_String; > when Integer_Type => > Integer_Value : Integer; > when Float_Type => > The_Value : Float; > end case; > end record; > > type Name_Value_Sequence is array(Natural range <>) of Name_Value; > > The compiler says "unconstrained element type in array declaration", > ...right! > > I know Ada is a strong typed language, but sometimes information is only at > runtime available. Does anyone know some workaround, or a regulare design > pattern for this problem? So, to summarise the various answers to this question, you could use indirection or default discriminants. An example of using indirection: type Name_Value_Ptr is access Name_Value; type Name_Value_Sequence is array (Natural range <>) of Name_Value_Ptr; Here Name_Value_Ptr is a pool-specific access type. You can create values of the designated type (Name_Value) by allocating them (generally in an area of memory called the 'heap'). For example: function "+" (Right: String) return Unbounded_String renames To_Unbounded_String; X: Name_Value_Sequence(0..9); ... X(5) := new Name_Value'( Integer_Type, +"Fred", 23 ); The amount of memory space used up by the allocated value will be the space required for the actual components selected by the discriminant (in this case Integer_Value) plus the mandatory components (in this case The_Name) plus (usually) the discriminants themselves (in this case Value_Type) plus whatever administrative information is required (associated with the management of the heap). Usually the administrative information is small (sometimes it is zero). We should also count the size of the access value in the array. Usually an access value is also small. Another example of using indirection: type Name_Value_Ptr is access all Name_Value; type Name_Value_Sequence is array (Natural range <>) of Name_Value_Ptr; Here Name_Value_Ptr is a general access type (note the 'all' in the declaration). You can create values of the designated type (Name_Value) by allocating them as before. However, you can also refer to aliased objects anywhere in memory. For example: function "+" (Right: String) return Unbounded_String renames To_Unbounded_String; X: Name_Value_Sequence(0..9); ... Y: aliased Name_Value := ( Integer_Type, +"Fred", 23 ); ... X(5) := Y'Access; The memory used by this technique is the same, except that if we do not allocate objects in the heap, we avoid the space used up by the administrative information (however much that is). A general access type may be bigger than a pool-specific one (but I think they are usually the same size, in fact). Finally, an example of using default discriminants: type Name_Value (Value_Type : Name_Value_Type := String_Type) is record ... type Name_Value_Sequence is array (Natural range <>) of Name_Value; ... X: Name_Value_Sequence(0..9); ... X(5) := ( Integer_Type, +"Fred", 23 ); The memory space used up by each component of the array will be the space required for the maximum of the union of the size of every component which could be selected by the discriminant (in this case the greatest of the sizes of String_Value, Integer_Value, and The_Value) plus the mandatory components (in this case The_Name) plus (usually) the discriminants themselves (in this case Value_Type). Therefore, if your discriminated record has some variants that are much bigger than others, this option could be very wasteful of memory space. On the other hand, if the variants are all of similar size (or memory space is not a major worry), this option could be the best, since it involves no indirection, no allocation, and no administrative information. There are many other possible ways of resolving the problem. One idea is to have separate arrays, one for each variation. This approach allows you to make each array of an appropriate length. For example, if you know that most of your values will be Float_Type, you could make that array big, and the other two small. The disadvantage of this approach is that you have to solve the problem of other data referring to array components: now there are many arrays, the right array has to be selected in addition to an index into the array. One advantage is that you do not have to store the discriminants, as such; in some cases this could save a lot of memory. A possible alternative to using an array is to use a structure with pointers (usually access values) to form a linked list, a tree, or whichever structure suits the data and the way it needs to be accessed. Typically, most of the hard work can be taken out of this approach by taking advantage of one of the various 'container' types provided by libraries such as Charles: http://home.earthlink.net/~matthewjheaney/charles/ Some containers are able to contain indefinite types (such as a record with discriminants without default values), and can provide various convenient ways of accessing the data too. A radical solution is to bypass the typing system. You have an array of small memory buffers, or you just have one big memory buffer (just like the heap), and store things in there in an encoding that suits the data. This approach can be a lot of work (especially to debug), and it may require a trade-off between memory use and speed of access, but it can be a very efficient option. In a few cases, it may be the only practical option. Finally, it should be mentioned that an alternative to using a single discriminant to simply select one of a set of variants is to use a hierarchy of tagged types. For example: type Root_Name_Value_Pair is abstract tagged record The_Name : Unbounded_String; end record; type Name_String_Pair is new Root_Name_Value_Pair with record String_Value : Unbounded_String; end record; type Name_Integer_Pair is new Root_Name_Value_Pair with record Integer_Value : Integer; end record; type Name_Float_Pair is new Root_Name_Value_Pair with record The_Value : Float; end record; type Name_Value_Access is access Root_Name_Value_Pair'Class; type Name_Value_Sequence is array (Positive range <>) of Name_Value_Access; With tagged types, it is usually necessary to use indirection (access types) to cope with the fact that polymorphism almost inevitably involves indefinite types. The alleged advantages of this approach vary from the subtle and arguable ("it is clearer") to the sure but possibly more complex: each different type within the hierarchy can have its own 'overriding' body of a subprogram; the hierarchy can be extended (in separate library units) without disturbing the existing source text. A call can dynamically select the correct body of an overridden subprogram, based on the tag of a parameter; this is a very neat technique, but it isn't always necessarily the better choice. Note that in the above example I've used Positive for the 'confinement' subtype of the array. It is my habit to do this for arrays used in this typical 'sequence' role, just like Ada's standard String type. People used to C arrays might prefer Natural. It can be significant if positional array aggregates are used, since the lower bound will determined by the confinement subtype (1 for Positive or 0 for Natural). Some food for thought, hopefully! -- Nick Roberts ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: How to define an array of a variant record type? 2003-11-18 17:48 ` Nick Roberts @ 2003-11-19 2:38 ` Steve 2003-11-19 8:11 ` Preben Randhol 2003-11-19 13:26 ` Rodrigo Garcia 1 sibling, 1 reply; 12+ messages in thread From: Steve @ 2003-11-19 2:38 UTC (permalink / raw) One other thing I can't resist mentioning. Here is a snippet of Ada Code in oue of our systems. TYPE aConstantDataItemCAX (itemTypeCAX : aConstantDataTypeCAX := invalidTypeCAX) IS RECORD CASE itemTypeCAX IS WHEN invalidTypeCAX | iTypeCAX => --The data item that is used to pass data between screen edit --and the access procedures intValueCAX : integer; WHEN fTypeCAX => realValueCAX : float; WHEN eTypeCAX => eValueCAX : anEnumRecordCAX; WHEN sTypeCAX => stringValueCAX : aConstantStringCAX; END CASE; END RECORD; Funny how the same ideas come up again and again. The original code was written in Pascal around 1987. Steve (The Duck) ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: How to define an array of a variant record type? 2003-11-19 2:38 ` Steve @ 2003-11-19 8:11 ` Preben Randhol 0 siblings, 0 replies; 12+ messages in thread From: Preben Randhol @ 2003-11-19 8:11 UTC (permalink / raw) On 2003-11-19, Steve <nospam_steved94@comcast.net> wrote: > One other thing I can't resist mentioning. > > Here is a snippet of Ada Code in oue of our systems. > > TYPE aConstantDataItemCAX (itemTypeCAX : aConstantDataTypeCAX := > invalidTypeCAX) IS > RECORD > CASE itemTypeCAX IS > WHEN invalidTypeCAX | iTypeCAX => > --The data item that is used to pass data between screen edit > --and the access procedures > intValueCAX : integer; > WHEN fTypeCAX => > realValueCAX : float; > WHEN eTypeCAX => > eValueCAX : anEnumRecordCAX; > WHEN sTypeCAX => > stringValueCAX : aConstantStringCAX; > END CASE; > END RECORD; Wouldn't underscores been nice? -- "Saving keystrokes is the job of the text editor, not the programming language." ^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: How to define an array of a variant record type? 2003-11-18 17:48 ` Nick Roberts 2003-11-19 2:38 ` Steve @ 2003-11-19 13:26 ` Rodrigo Garcia 1 sibling, 0 replies; 12+ messages in thread From: Rodrigo Garcia @ 2003-11-19 13:26 UTC (permalink / raw) > So, to summarise the various answers to this question, you could use > indirection or default discriminants. There is a third possibility. Use tagged types instead of variant records and... welcome to the wonderful world of OO programming in Ada ;^) Rodrigo ^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2003-11-20 10:02 UTC | newest] Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2003-11-17 16:57 How to define an array of a variant record type? Harald Schmidt 2003-11-17 17:35 ` Stephen Leake 2003-11-20 10:02 ` Craig Carey 2003-11-17 17:37 ` Marius Amado Alves 2003-11-18 2:48 ` Steve 2003-11-18 9:04 ` Marius Amado Alves 2003-11-17 18:45 ` Rodrigo Garcia 2003-11-18 2:48 ` Steve 2003-11-18 17:48 ` Nick Roberts 2003-11-19 2:38 ` Steve 2003-11-19 8:11 ` Preben Randhol 2003-11-19 13:26 ` Rodrigo Garcia
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox