comp.lang.ada
 help / color / mirror / Atom feed
* Problem with Position of the enumeration Type
@ 2019-01-23 10:05 Luis Ladron de Guevara Moreno
  2019-01-23 10:33 ` AdaMagica
                   ` (3 more replies)
  0 siblings, 4 replies; 25+ messages in thread
From: Luis Ladron de Guevara Moreno @ 2019-01-23 10:05 UTC (permalink / raw)


Hello,

I have an issue with the declaration of the enumeration type, when i try to map the values of an enumeration to a specific position.

the code:

procedure EnumerationTest is

   Position : Integer;
   
   type E_Test is (Pos10, Pos11, Pos12, Pos13, Pos14);

   for E_Test use (Pos10 => 10,
                   Pos11 => 11,
                   Pos12 => 12,
                   Pos13 => 13,
                   Pos14 => 14);

begin

   for I in E_Test'Base loop
      
      Position := E_Test'pos (I);
      ada.Text_IO.Put (" Position: " & Position'Img & " Value: " & I'Img);
   end loop;

end EnumerationTest;

i thought that the result of the position was 10, 11, 12, 13, 14. But When i run this code, the result is 0, 1, 2, 3. I don't know what it is the exactly meaning of:
   
for E_Test use (Pos10 => 10,
                   Pos11 => 11,
                   Pos12 => 12,
                   Pos13 => 13,
                   Pos14 => 14);

and how can i assign a different position for the specific value.
Could anyone help me with this problem?

Thank you so much =)


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Problem with Position of the enumeration Type
  2019-01-23 10:05 Problem with Position of the enumeration Type Luis Ladron de Guevara Moreno
@ 2019-01-23 10:33 ` AdaMagica
  2019-01-23 10:55   ` AdaMagica
  2019-01-23 12:08   ` Luis Ladron de Guevara Moreno
  2019-01-23 11:32 ` Mark Lorenzen
                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 25+ messages in thread
From: AdaMagica @ 2019-01-23 10:33 UTC (permalink / raw)


See RM 13.4(11/3)ff:
NOTES
14 Unchecked_Conversion may be used to query the internal codes used for
an enumeration type. The attributes of the type, such as Succ, Pred, and Pos, are unaffected by the enumeration_representation_clauserepresentation_clause.

Some questions on your code:

  Position : Integer;  -- Why is this Integer and not Natural?
   
  for I in E_Test'Base loop  -- Why do you use 'Base here?

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Problem with Position of the enumeration Type
  2019-01-23 10:33 ` AdaMagica
@ 2019-01-23 10:55   ` AdaMagica
  2019-01-23 12:08   ` Luis Ladron de Guevara Moreno
  1 sibling, 0 replies; 25+ messages in thread
From: AdaMagica @ 2019-01-23 10:55 UTC (permalink / raw)


See RM 3.5.1(7):
The position number of the value of the first listed enumeration literal is zero; the position number of the value of each subsequent enumeration literal is one more than that of its predecessor in the list.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Problem with Position of the enumeration Type
  2019-01-23 10:05 Problem with Position of the enumeration Type Luis Ladron de Guevara Moreno
  2019-01-23 10:33 ` AdaMagica
@ 2019-01-23 11:32 ` Mark Lorenzen
  2019-01-23 12:30   ` Luis Ladron de Guevara Moreno
  2019-01-23 17:06 ` Simon Wright
  2019-01-23 21:42 ` Niklas Holsti
  3 siblings, 1 reply; 25+ messages in thread
From: Mark Lorenzen @ 2019-01-23 11:32 UTC (permalink / raw)


On Wednesday, January 23, 2019 at 11:06:01 AM UTC+1, Luis Ladron de Guevara Moreno wrote:
> Hello,
> 
> I have an issue with the declaration of the enumeration type, when i try to map the values of an enumeration to a specific position.
> 
> the code:
> 
> procedure EnumerationTest is
> 
>    Position : Integer;
>    
>    type E_Test is (Pos10, Pos11, Pos12, Pos13, Pos14);
> 
>    for E_Test use (Pos10 => 10,
>                    Pos11 => 11,
>                    Pos12 => 12,
>                    Pos13 => 13,
>                    Pos14 => 14);
> 
> begin
> 
>    for I in E_Test'Base loop
>       
>       Position := E_Test'pos (I);
>       ada.Text_IO.Put (" Position: " & Position'Img & " Value: " & I'Img);
>    end loop;
> 
> end EnumerationTest;
> 
> i thought that the result of the position was 10, 11, 12, 13, 14. But When i run this code, the result is 0, 1, 2, 3. I don't know what it is the exactly meaning of:
>    
> for E_Test use (Pos10 => 10,
>                    Pos11 => 11,
>                    Pos12 => 12,
>                    Pos13 => 13,
>                    Pos14 => 14);
> 
> and how can i assign a different position for the specific value.
> Could anyone help me with this problem?
> 
> Thank you so much =)

What problem are you trying to solve? Defining the representation of enumeration values is normally only useful when doing I/O i.e. when you need to map an integer value to an enumeration value.

Regards,

Mark L

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Problem with Position of the enumeration Type
  2019-01-23 10:33 ` AdaMagica
  2019-01-23 10:55   ` AdaMagica
@ 2019-01-23 12:08   ` Luis Ladron de Guevara Moreno
  2019-01-23 12:15     ` Karl Müller
                       ` (2 more replies)
  1 sibling, 3 replies; 25+ messages in thread
From: Luis Ladron de Guevara Moreno @ 2019-01-23 12:08 UTC (permalink / raw)


El miércoles, 23 de enero de 2019, 11:33:36 (UTC+1), AdaMagica  escribió:
> See RM 13.4(11/3)ff:
> NOTES
> 14 Unchecked_Conversion may be used to query the internal codes used for
> an enumeration type. The attributes of the type, such as Succ, Pred, and Pos, are unaffected by the enumeration_representation_clauserepresentation_clause.
> 
> Some questions on your code:
> 
>   Position : Integer;  -- Why is this Integer and not Natural?
>    
>   for I in E_Test'Base loop  -- Why do you use 'Base here?

I wrote a Integer as an example, i could add Natural also, for this example there are not difference.

I'm using 'Range to go through all the positions in enumeration.

I tried to use Ada.Unchecked_Conversion and i got obtain the values for the position. but as you told me, if i use 'post (), the number of the list start in 0.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Problem with Position of the enumeration Type
  2019-01-23 12:08   ` Luis Ladron de Guevara Moreno
@ 2019-01-23 12:15     ` Karl Müller
  2019-01-23 21:50     ` Niklas Holsti
  2019-01-24  8:06     ` AdaMagica
  2 siblings, 0 replies; 25+ messages in thread
From: Karl Müller @ 2019-01-23 12:15 UTC (permalink / raw)


For GNAT the Attribute 'Enum_Rep could be helpful:

  ada.Text_IO.Put
  (" Position: " & Position'Img & " Value: " & I'Enum_Rep'Img);

Result:

Position:  0 Value:  10 Position:  1 Value:  11 Position:  2 Value:  12 
Position:  3 Value:  13 Position:  4 Value:  14

Regards
Karl


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Problem with Position of the enumeration Type
  2019-01-23 11:32 ` Mark Lorenzen
@ 2019-01-23 12:30   ` Luis Ladron de Guevara Moreno
  2019-01-23 20:22     ` Shark8
  0 siblings, 1 reply; 25+ messages in thread
From: Luis Ladron de Guevara Moreno @ 2019-01-23 12:30 UTC (permalink / raw)


El miércoles, 23 de enero de 2019, 12:32:49 (UTC+1), Mark Lorenzen  escribió:
> On Wednesday, January 23, 2019 at 11:06:01 AM UTC+1, Luis Ladron de Guevara Moreno wrote:
> > Hello,
> > 
> > I have an issue with the declaration of the enumeration type, when i try to map the values of an enumeration to a specific position.
> > 
> > the code:
> > 
> > procedure EnumerationTest is
> > 
> >    Position : Integer;
> >    
> >    type E_Test is (Pos10, Pos11, Pos12, Pos13, Pos14);
> > 
> >    for E_Test use (Pos10 => 10,
> >                    Pos11 => 11,
> >                    Pos12 => 12,
> >                    Pos13 => 13,
> >                    Pos14 => 14);
> > 
> > begin
> > 
> >    for I in E_Test'Base loop
> >       
> >       Position := E_Test'pos (I);
> >       ada.Text_IO.Put (" Position: " & Position'Img & " Value: " & I'Img);
> >    end loop;
> > 
> > end EnumerationTest;
> > 
> > i thought that the result of the position was 10, 11, 12, 13, 14. But When i run this code, the result is 0, 1, 2, 3. I don't know what it is the exactly meaning of:
> >    
> > for E_Test use (Pos10 => 10,
> >                    Pos11 => 11,
> >                    Pos12 => 12,
> >                    Pos13 => 13,
> >                    Pos14 => 14);
> > 
> > and how can i assign a different position for the specific value.
> > Could anyone help me with this problem?
> > 
> > Thank you so much =)
> 
> What problem are you trying to solve? Defining the representation of enumeration values is normally only useful when doing I/O i.e. when you need to map an integer value to an enumeration value.
> 
> Regards,
> 
> Mark L

My problem is that i thougth that when i write: 

 for E_Test use (Pos10 => 10,
                  Pos11 => 11,
                    Pos12 => 12,
                    Pos13 => 13,
                    Pos14 => 14);

the numbers 10, 11, 12... was the position of the enumeration and when i tried to use ex. 'Pos(Pos12) i obtained a  2. The position of the values cannot be modified. these values are the representation of the enum, i understand.


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Problem with Position of the enumeration Type
  2019-01-23 10:05 Problem with Position of the enumeration Type Luis Ladron de Guevara Moreno
  2019-01-23 10:33 ` AdaMagica
  2019-01-23 11:32 ` Mark Lorenzen
@ 2019-01-23 17:06 ` Simon Wright
  2019-01-23 22:54   ` Randy Brukardt
  2019-01-23 21:42 ` Niklas Holsti
  3 siblings, 1 reply; 25+ messages in thread
From: Simon Wright @ 2019-01-23 17:06 UTC (permalink / raw)


Luis Ladron de Guevara Moreno <luis33.lgm@gmail.com> writes:

>    type E_Test is (Pos10, Pos11, Pos12, Pos13, Pos14);
>
>    for E_Test use (Pos10 => 10,
>                    Pos11 => 11,
>                    Pos12 => 12,
>                    Pos13 => 13,
>                    Pos14 => 14);

> i thought that the result of the position was 10, 11, 12, 13, 14. But
> When i run this code, the result is 0, 1, 2, 3.

As Karl Müller <mtb23@gmx.de> hinted, you can use the non-standard GNAT
implementation-defined attribute 'Enum_Rep[1]. The next page describes
'Enum_Val.

[1] https://gcc.gnu.org/onlinedocs/gnat_rm/Attribute-Enum_005fRep.html

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Problem with Position of the enumeration Type
  2019-01-23 12:30   ` Luis Ladron de Guevara Moreno
@ 2019-01-23 20:22     ` Shark8
  2019-01-24  8:13       ` AdaMagica
  0 siblings, 1 reply; 25+ messages in thread
From: Shark8 @ 2019-01-23 20:22 UTC (permalink / raw)


On Wednesday, January 23, 2019 at 5:30:24 AM UTC-7, Luis Ladron de Guevara Moreno wrote:
>
> the numbers 10, 11, 12... was the position of the enumeration and when i tried to use ex. 'Pos(Pos12) i obtained a  2. The position of the values cannot be modified. these values are the representation of the enum, i understand.

That's correct -- 'Pos gives you the position in the ordered-set of the enumeration, and 'Val does the inverse.

What you want is Unchecked_Conversion, to do this well you want to specify the sizes so they match up.

Type Enum_Reps is range 10..14 -- You could hide this in the private section,
  with Size => Natural'Size;   -- and have renaming-as-a-body for the actual
                               -- conversion functions.

Function Convert is new Unchecked_Conversion( E_Test, Enum_Reps );
Function Convert is new Unchecked_Conversion( Enum_Reps, E_Test );

and then just use Convert.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Problem with Position of the enumeration Type
  2019-01-23 10:05 Problem with Position of the enumeration Type Luis Ladron de Guevara Moreno
                   ` (2 preceding siblings ...)
  2019-01-23 17:06 ` Simon Wright
@ 2019-01-23 21:42 ` Niklas Holsti
  2019-01-23 22:35   ` Simon Wright
  2019-01-26  9:44   ` G.B.
  3 siblings, 2 replies; 25+ messages in thread
From: Niklas Holsti @ 2019-01-23 21:42 UTC (permalink / raw)


On 19-01-23 12:05 , Luis Ladron de Guevara Moreno wrote:
> Hello,
>
> I have an issue with the declaration of the enumeration type,
> when i try to map the values of an enumeration to a specific position.
>
> the code:
>
> procedure EnumerationTest is
>
>    Position : Integer;
>
>    type E_Test is (Pos10, Pos11, Pos12, Pos13, Pos14);
>
>    for E_Test use (Pos10 => 10,
>                    Pos11 => 11,
>                    Pos12 => 12,
>                    Pos13 => 13,
>                    Pos14 => 14);
>
> begin
>
>    for I in E_Test'Base loop
>
>       Position := E_Test'pos (I);
>       ada.Text_IO.Put (" Position: " & Position'Img & " Value: " & I'Img);
>    end loop;
>
> end EnumerationTest;
>
> i thought that the result of the position was 10,
> 11, 12, 13, 14. But When i run this code, the result
> is 0, 1, 2, 3. I don't know what it is the exactly meaning of:
>
> for E_Test use (Pos10 => 10,
>                 Pos11 => 11,
>                 Pos12 => 12,
>                 Pos13 => 13,
>                 Pos14 => 14);
>
> and how can i assign a different position for the specific value.

The point is that Ada enumeration literals are not merely synonyms for 
integer values, unlike C enums.

The list of names (enumeration literals) in the declaration of the 
enumerated type defines the position numbers, which always start from 0 
and increase by 1 for each literal. These position numbers, which can be 
queried with the 'Pos attribute, are independent of the possible "for .. 
use" representation clause for the enumeration.

On the next level -- physical representation -- if you have code like

    E : E_Test;
    ...
    E := Pos12;

you can ask as follows: The compiler allocates a memory location for the 
object E. Let's say that an octet of 8 bits is allocated. What are the 
values of these 8 bits after the assignment of Pos12 to E? In other 
words, which bit pattern in memory represents the logical value Pos12?

This question is answered by the presence (or absence) of a "for E_Test 
use" representation clause:

- if there is no such clause, the value of the bits is given by the 
position number, which for Pos12 is 2 (2#0000_0010# in binary)

- if there is such a clause, the value of the bits is given by the 
representation value in that clause, which for Pos12 is 12 (binary 
2#0000_1100#) using the values in your example.

As others have remarked, you can discover the representation value by an 
Unchecked_Conversion from E_Test to some integer type (with the same 
number of bits), or by the GNAT-specific attribute 'Enum_Rep.

In your example, the representation values are contiguous, but there can 
also be gaps, for example:

    for E_Test use (Pos10 => 10,
                    Pos11 => 21,
                    Pos12 => 34,
                    Pos13 => 100,
                    Pos14 => 255);

(However, the representation values must be in ascending order, so that 
their order is the same as the position-number order.)

The important points to note are that the 'Pos values still run from 0 
to 4, and most importantly that the 'Succ and 'Pred attribute functions 
"skip" the gaps, so that, for example,

    E := E_Test'Succ (Pos11);

makes E = Pos12, represented in memory as 34. Thus, 'Succ is not just 
"add one to the value", but "take the next representation value".

As an aside, this means that 'Succ and 'Pred on enumeration types with 
"gappy" representations can be much more expensive (in processor time) 
than for enumeration types with gap-less representations or default 
representations. For this reason, Ada design and coding rules for 
embedded/critical systems often place restrictions on enumeration types 
with representation clauses, for example that 'Succ, 'Pred and the like 
should not be used for such types. Such rules also commonly say that 
such types should not be used as array index types, because of the 
possible introduction of gaps in the array representations.

Furthermore, if you loop over an enumeration with a gappy 
representations, such as

    for E in E_Test loop ... end loop;

the loop will use _only_ the valid representations. So the bits holding 
the value of the loop-counter E will successively take on the values 10, 
21, 34, 100, 255, but will skip the values in between. This is quite 
different from what would happen in C.

As others have also noted, enumeration representation clauses are used 
mostly when the enumeration value is an input (say, from some 
memory-mapped control register, or from a binary input file) or an 
output. Communication protocols and HW interfaces often define fields 
that encode some finite set of possible logical values/meanings, but 
where the encoding has gaps.

A final note: if you use an enumerated type for an input value, it is 
wise to check if the input is valid before using it. Use the 'Valid 
attribute for this. However, this attribute can also have a non-trivial 
cost. For example, the compiler may implement the function call 
E_Test'Valid(E) by code that compares the (representation of) E against 
each of the valid values 10, 21, 34, 100, 255 in turn (although a better 
compiler would use a binary search).

An alternative I often use is to define the enumerated type with default 
representation (= position numbers), define the input as an integer (in 
this case 0 .. 255), and translate from input to enumeration with an 
array, like this:

    type Input_Value is range 0 .. 255;

    E_For_Input : constant array (Input_Value) of E_Test is := (
        10 => Pos10,
        21 => Pos11,
        34 => Pos12,
       100 => Pos13,
       255 => Pos14,
       others => Pos_Invalid);

where I assume that E_Test is extended with the literal Pos_Invalid. 
Given an input value In, the corresponding enumeration value E is 
obtained by E := E_For_Input(I), and validity can be checked by "if E /= 
Pos_Invalid then ..." instead of using E_Test'Valid.

A similar translation can be used to map an internal enumeration (with 
default representation) to an external, gappy, output encoding.

These alternatives (array-based translations) have the advantage, 
compared to enumeration representation clauses, that the representation 
values (external input/output values) can use a different order than the 
enumerated type. This can make it easier to define logical subtypes 
(sub-ranges) of the enumerated type.

-- 
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
       .      @       .


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Problem with Position of the enumeration Type
  2019-01-23 12:08   ` Luis Ladron de Guevara Moreno
  2019-01-23 12:15     ` Karl Müller
@ 2019-01-23 21:50     ` Niklas Holsti
  2019-01-24  8:06     ` AdaMagica
  2 siblings, 0 replies; 25+ messages in thread
From: Niklas Holsti @ 2019-01-23 21:50 UTC (permalink / raw)


On 19-01-23 14:08 , Luis Ladron de Guevara Moreno wrote:
> El miércoles, 23 de enero de 2019, 11:33:36 (UTC+1), AdaMagica  escribió:
>> ...
>> Some questions on your code:
>> ...
>>
>>   for I in E_Test'Base loop  -- Why do you use 'Base here?
> ...
> I'm using 'Range to go through all the positions in enumeration.

You misread AdaMagica's question, which was about 'Base (which you use), 
not about 'Range (which you did not use).

In your code, as E_Test is a not a subtype of some wider enumeration 
type, E_Test'Base is the same as E_Test.

Regarding 'Range, note that

    for E in E_Test'Range loop ... end loop;

can be written simply as

    for E in E_Test loop ... end loop;

with exactly the same effect.

Now: did you mean to write 'Base (and not 'Range), and if so, why?

-- 
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
       .      @       .

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Problem with Position of the enumeration Type
  2019-01-23 21:42 ` Niklas Holsti
@ 2019-01-23 22:35   ` Simon Wright
  2019-01-23 23:20     ` Niklas Holsti
  2019-01-24 16:43     ` Jeffrey R. Carter
  2019-01-26  9:44   ` G.B.
  1 sibling, 2 replies; 25+ messages in thread
From: Simon Wright @ 2019-01-23 22:35 UTC (permalink / raw)


Niklas Holsti <niklas.holsti@tidorum.invalid> writes:

> Such rules also commonly say that such types should not be used as
> array index types, because of the possible introduction of gaps in the
> array representations.

Not, it seems, with GNAT:

   $ cat gappy.adb
   with Ada.Text_IO; use Ada.Text_IO;
   procedure Gappy is
      type E_Test is (Pos10, Pos11, Pos12, Pos13, Pos14);
      for E_Test use (Pos10 => 100,
                      Pos11 => 110,
                      Pos12 => 120,
                      Pos13 => 130,
                      Pos14 => 255);
      type Arr is array (E_Test) of Integer;
   begin
      Put_Line ("Arr's size is"
                  & Arr'Max_Size_In_Storage_Elements'Img
                  & " bytes.");
   end Gappy;
   
   $ gnatmake -f gappy
   gcc -c gappy.adb
   gnatbind -x gappy.ali
   gnatlink gappy.ali

   $ ./gappy
   Arr's size is 20 bytes.

I'd think any other behaviour would be unreasonable (though I can't see
any statement about it in the ARM).

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Problem with Position of the enumeration Type
  2019-01-23 17:06 ` Simon Wright
@ 2019-01-23 22:54   ` Randy Brukardt
  2019-01-23 23:47     ` Keith Thompson
  0 siblings, 1 reply; 25+ messages in thread
From: Randy Brukardt @ 2019-01-23 22:54 UTC (permalink / raw)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 419 bytes --]

"Simon Wright" <simon@pushface.org> wrote in message 
news:lyzhrruww2.fsf@pushface.org...
...
> As Karl Müller <mtb23@gmx.de> hinted, you can use the non-standard GNAT
> implementation-defined attribute 'Enum_Rep[1]. The next page describes
> 'Enum_Val.

It's Standard, just not until Ada 2020. See 
http://www.ada-auth.org/standards/2xrm/html/RM-13-4.html#p10.1.

(Yes, borrowed from GNAT.)

                  Randy.


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Problem with Position of the enumeration Type
  2019-01-23 22:35   ` Simon Wright
@ 2019-01-23 23:20     ` Niklas Holsti
  2019-01-24 16:43     ` Jeffrey R. Carter
  1 sibling, 0 replies; 25+ messages in thread
From: Niklas Holsti @ 2019-01-23 23:20 UTC (permalink / raw)


On 19-01-24 00:35 , Simon Wright wrote:
> Niklas Holsti <niklas.holsti@tidorum.invalid> writes:
>
>> Such rules also commonly say that such types should not be used as
>> array index types, because of the possible introduction of gaps in the
>> array representations.
>
> Not, it seems, with GNAT:

      [skip example]

Nice to know.

> I'd think any other behaviour would be unreasonable (though I can't see
> any statement about it in the ARM).

Avoiding gaps in such arrays means that GNAT is effectively using the 
position number as the (machine-level) index, which means that indexing 
with an arbitrary enumeration value (not a loop induction variable) 
requires the use of the 'Pos function, with its possible longish 
execution time for a gappy enumeration. So it's a space vs time 
trade-off, and GNAT chooses to reduce space at the cost of time.

I too think that this is the choice less likely to surprise users.

While enumeration representation clauses are a logical and sometimes 
useful feature, they are not very often the best design approach -- or 
not as often as one first thinks, when learning about them. I tend to 
use them only for outputs on the HW level, not so much for inputs 
(because of the need for validity checking that I commented on).

-- 
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
       .      @       .


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Problem with Position of the enumeration Type
  2019-01-23 22:54   ` Randy Brukardt
@ 2019-01-23 23:47     ` Keith Thompson
  2019-01-24  4:34       ` Keith Thompson
  2019-01-24 21:41       ` Randy Brukardt
  0 siblings, 2 replies; 25+ messages in thread
From: Keith Thompson @ 2019-01-23 23:47 UTC (permalink / raw)


"Randy Brukardt" <randy@rrsoftware.com> writes:
> "Simon Wright" <simon@pushface.org> wrote in message 
> news:lyzhrruww2.fsf@pushface.org...
> ...
>> As Karl Müller <mtb23@gmx.de> hinted, you can use the non-standard GNAT
>> implementation-defined attribute 'Enum_Rep[1]. The next page describes
>> 'Enum_Val.
>
> It's Standard, just not until Ada 2020. See 
> http://www.ada-auth.org/standards/2xrm/html/RM-13-4.html#p10.1.
>
> (Yes, borrowed from GNAT.)

I'm glad to see this being standardized.

Unchecked_Conversion can be a workaround, but it's difficult
(perhaps impossible) to portably determine the integer type to
which you need to convert.

For example, both of these are valid:

    type Unsigned_Byte is (UMin, UMax);
    for Unsigned_Byte use (0, 255);
    for Unsigned_Byte'Size use 8;

    type Signed_Byte is (SMin, SMax);
    for Signed_Byte use (-128, 127);
    for Signed_Byte'Size use 8;

Both types will have the same representation for the min and max values.
How can you *portably* determine the appropriate target type for an
Unchecked_Conversion that yields the correct values?

(You can do it manually on a case by case basis.)

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Problem with Position of the enumeration Type
  2019-01-23 23:47     ` Keith Thompson
@ 2019-01-24  4:34       ` Keith Thompson
  2019-01-24  9:11         ` Simon Wright
  2019-01-24 21:41       ` Randy Brukardt
  1 sibling, 1 reply; 25+ messages in thread
From: Keith Thompson @ 2019-01-24  4:34 UTC (permalink / raw)


Keith Thompson <kst-u@mib.org> writes:
> "Randy Brukardt" <randy@rrsoftware.com> writes:
>> "Simon Wright" <simon@pushface.org> wrote in message 
>> news:lyzhrruww2.fsf@pushface.org...
>> ...
>>> As Karl Müller <mtb23@gmx.de> hinted, you can use the non-standard GNAT
>>> implementation-defined attribute 'Enum_Rep[1]. The next page describes
>>> 'Enum_Val.
>>
>> It's Standard, just not until Ada 2020. See 
>> http://www.ada-auth.org/standards/2xrm/html/RM-13-4.html#p10.1.
>>
>> (Yes, borrowed from GNAT.)
>
> I'm glad to see this being standardized.

GNAT 7.30 has a bug in its implementation of the 'Enum_Val attribute.
In some cases, it appears to examine only the low-order bits of the
argument, causing it to yield a valid value when it should raise
Constraint_Error.

A demo:

    with Ada.Text_IO; use Ada.Text_IO;
    procedure Enum_Bug is
        type Enum is (Two, Four);
        for Enum use (2, 4);
    begin
        for I in 10 .. 11 loop
            begin
                Put(Integer'Image(I) & ": ");
                Put_Line(Enum'Image(Enum'Enum_Val(I)));
            exception
                when Constraint_Error =>
                    Put_Line("Constraint_Error");
            end;
        end loop;
    end Enum_Bug;

Expected output:

     10: Constraint_Error
     11: Constraint_Error

Actual output:

     10: TWO
     11: Constraint_Error

I'll also report this via https://www.adacore.com/community/contact

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Problem with Position of the enumeration Type
  2019-01-23 12:08   ` Luis Ladron de Guevara Moreno
  2019-01-23 12:15     ` Karl Müller
  2019-01-23 21:50     ` Niklas Holsti
@ 2019-01-24  8:06     ` AdaMagica
  2 siblings, 0 replies; 25+ messages in thread
From: AdaMagica @ 2019-01-24  8:06 UTC (permalink / raw)


Am Mittwoch, 23. Januar 2019 13:08:34 UTC+1 schrieb Luis Ladron de Guevara Moreno:
> El miércoles, 23 de enero de 2019, 11:33:36 (UTC+1), AdaMagica  escribió:
> > See RM 13.4(11/3)ff:
> > NOTES
> > 14 Unchecked_Conversion may be used to query the internal codes used for
> > an enumeration type. The attributes of the type, such as Succ, Pred, and Pos, are unaffected by the enumeration_representation_clauserepresentation_clause.
> > 
> > Some questions on your code:
> > 
> >   Position : Integer;  -- Why is this Integer and not Natural?
> >    
> >   for I in E_Test'Base loop  -- Why do you use 'Base here?
> 
> I wrote a Integer as an example, i could add Natural also, for this example there are not difference.

It does make a difference. Ada has subtypes just for this purpose: If you know that the values of an object of some type belong only to some subtype, you indicate this in the declaration.
This is the very idea of stong typing.

> I'm using 'Range to go through all the positions in enumeration.

No, you used 'Base.

For a enum type E, these are always the same:

for V in E loop
for V in E'Range loop

For an enum type that is not derived, E'Base is the same as E. For types derived from E, there might be a difference.

> I tried to use Ada.Unchecked_Conversion and i got obtain the values for the position. but as you told me, if i use 'post (), the number of the list start in 0.

Yes, this is what the RM prescribes.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Problem with Position of the enumeration Type
  2019-01-23 20:22     ` Shark8
@ 2019-01-24  8:13       ` AdaMagica
  0 siblings, 0 replies; 25+ messages in thread
From: AdaMagica @ 2019-01-24  8:13 UTC (permalink / raw)


Am Mittwoch, 23. Januar 2019 21:22:09 UTC+1 schrieb Shark8:
> What you want is Unchecked_Conversion, to do this well you want to specify the sizes so they match up.

Tht's correct, sizes of source and target must be same.

> Type Enum_Reps is range 10..14 -- You could hide this in the private section,
>   with Size => Natural'Size;   -- and have renaming-as-a-body for the actual
>                                -- conversion functions.

But this is wrong. Enum_Reps'Size (Natural as defined) is very different from E_Test'Size.

If you want to know what might happen in this case, see

http://www.christ-usch-grein.homepage.t-online.de/AdaMagica/Prokrustes-e.html

I was bitten by this when porting Ada code from one architeture and commpiler to a different archit. and comp.

> Function Convert is new Unchecked_Conversion( E_Test, Enum_Reps );
> Function Convert is new Unchecked_Conversion( Enum_Reps, E_Test );
> 
> and then just use Convert.


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Problem with Position of the enumeration Type
  2019-01-24  4:34       ` Keith Thompson
@ 2019-01-24  9:11         ` Simon Wright
  0 siblings, 0 replies; 25+ messages in thread
From: Simon Wright @ 2019-01-24  9:11 UTC (permalink / raw)


Keith Thompson <kst-u@mib.org> writes:

> GNAT 7.30 has a bug in its implementation of the 'Enum_Val attribute.
> In some cases, it appears to examine only the low-order bits of the
> argument, causing it to yield a valid value when it should raise
> Constraint_Error.

Same error in FSF GCC 8.1.0, 9.0.0.

> I'll also report this via https://www.adacore.com/community/contact

Better to <report@adacore.com>, I think


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Problem with Position of the enumeration Type
  2019-01-23 22:35   ` Simon Wright
  2019-01-23 23:20     ` Niklas Holsti
@ 2019-01-24 16:43     ` Jeffrey R. Carter
  2019-01-24 19:39       ` Niklas Holsti
  1 sibling, 1 reply; 25+ messages in thread
From: Jeffrey R. Carter @ 2019-01-24 16:43 UTC (permalink / raw)


On 1/23/19 11:35 PM, Simon Wright wrote:
> Niklas Holsti <niklas.holsti@tidorum.invalid> writes:
> 
>> Such rules also commonly say that such types should not be used as
>> array index types, because of the possible introduction of gaps in the
>> array representations.
> 
> Not, it seems, with GNAT:

This is not a language rule. I can find nothing in the ARM about disallowing 
such types as array indices. So naturally GNAT and all other compilers must 
support it.

-- 
Jeff Carter
"When and now is this guitar piece from Stottlemeyer?
Yes, it's with Mr. Dog in Gertrude's pinball forest."
The World's Funniest Joke
133

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Problem with Position of the enumeration Type
  2019-01-24 16:43     ` Jeffrey R. Carter
@ 2019-01-24 19:39       ` Niklas Holsti
  2019-01-24 20:29         ` Jeffrey R. Carter
  2019-01-24 21:43         ` Randy Brukardt
  0 siblings, 2 replies; 25+ messages in thread
From: Niklas Holsti @ 2019-01-24 19:39 UTC (permalink / raw)


On 19-01-24 18:43 , Jeffrey R. Carter wrote:
> On 1/23/19 11:35 PM, Simon Wright wrote:
>> Niklas Holsti <niklas.holsti@tidorum.invalid> writes:
>>
>>> Such rules also commonly say that such types should not be used as
>>> array index types, because of the possible introduction of gaps in the
>>> array representations.
>>
>> Not, it seems, with GNAT:
>
> This is not a language rule. I can find nothing in the ARM about
> disallowing such types as array indices. So naturally GNAT and all other
> compilers must support it.

All compliant compilers, yes. But the question was: if the enumerated 
index type has gaps in its representation, can there be corresponding 
gaps (unused intervals of storage units) between the elements of the 
array, as represented in memory? Or must the elements still be 
contiguous, except for alignment padding?

In other words, can the compiled code compute the offset of an array 
element directly from the representation of the enumerated index value 
(causing gaps in the array), or must it always first compute the 
position number of that value, and then compute the offset from the 
position number (suppressing gaps)?

This discussion has not yet pointed to an ARM rule that forbids gaps in 
the array's representation.

-- 
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
       .      @       .


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Problem with Position of the enumeration Type
  2019-01-24 19:39       ` Niklas Holsti
@ 2019-01-24 20:29         ` Jeffrey R. Carter
  2019-01-24 21:43         ` Randy Brukardt
  1 sibling, 0 replies; 25+ messages in thread
From: Jeffrey R. Carter @ 2019-01-24 20:29 UTC (permalink / raw)


On 1/24/19 8:39 PM, Niklas Holsti wrote:
> 
> All compliant compilers, yes. But the question was: if the enumerated index type 
> has gaps in its representation, can there be corresponding gaps (unused 
> intervals of storage units) between the elements of the array, as represented in 
> memory? Or must the elements still be contiguous, except for alignment padding?
> 
> In other words, can the compiled code compute the offset of an array element 
> directly from the representation of the enumerated index value (causing gaps in 
> the array), or must it always first compute the position number of that value, 
> and then compute the offset from the position number (suppressing gaps)?
> 
> This discussion has not yet pointed to an ARM rule that forbids gaps in the 
> array's representation.

In the absence of representation specifications (Component_Size, Pack, 
Convention), AFAIK the only thing that the ARM says about the implementation of 
arrays is that multidimensional arrays must be in row-major order. Other than 
that, it's up to the compiler, so any array could have "gaps", regardless of the 
index subtypes.

-- 
Jeff Carter
"When and now is this guitar piece from Stottlemeyer?
Yes, it's with Mr. Dog in Gertrude's pinball forest."
The World's Funniest Joke
133


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Problem with Position of the enumeration Type
  2019-01-23 23:47     ` Keith Thompson
  2019-01-24  4:34       ` Keith Thompson
@ 2019-01-24 21:41       ` Randy Brukardt
  1 sibling, 0 replies; 25+ messages in thread
From: Randy Brukardt @ 2019-01-24 21:41 UTC (permalink / raw)


"Keith Thompson" <kst-u@mib.org> wrote in message 
news:lnimyf0wee.fsf@kst-u.example.com...
> "Randy Brukardt" <randy@rrsoftware.com> writes:
...
> Both types will have the same representation for the min and max values.
> How can you *portably* determine the appropriate target type for an
> Unchecked_Conversion that yields the correct values?
>
> (You can do it manually on a case by case basis.)

But that's impossible in a generic unit. Which was the main reason for 
finally deciding to include these attributes.

                  Randy.


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Problem with Position of the enumeration Type
  2019-01-24 19:39       ` Niklas Holsti
  2019-01-24 20:29         ` Jeffrey R. Carter
@ 2019-01-24 21:43         ` Randy Brukardt
  1 sibling, 0 replies; 25+ messages in thread
From: Randy Brukardt @ 2019-01-24 21:43 UTC (permalink / raw)


"Niklas Holsti" <niklas.holsti@tidorum.invalid> wrote in message 
news:gauihgF9eu2U1@mid.individual.net...
> On 19-01-24 18:43 , Jeffrey R. Carter wrote:
>> On 1/23/19 11:35 PM, Simon Wright wrote:
>>> Niklas Holsti <niklas.holsti@tidorum.invalid> writes:
>>>
>>>> Such rules also commonly say that such types should not be used as
>>>> array index types, because of the possible introduction of gaps in the
>>>> array representations.
>>>
>>> Not, it seems, with GNAT:
>>
>> This is not a language rule. I can find nothing in the ARM about
>> disallowing such types as array indices. So naturally GNAT and all other
>> compilers must support it.
>
> All compliant compilers, yes. But the question was: if the enumerated 
> index type has gaps in its representation, can there be corresponding gaps 
> (unused intervals of storage units) between the elements of the array, as 
> represented in memory? Or must the elements still be contiguous, except 
> for alignment padding?
>
> In other words, can the compiled code compute the offset of an array 
> element directly from the representation of the enumerated index value 
> (causing gaps in the array), or must it always first compute the position 
> number of that value, and then compute the offset from the position number 
> (suppressing gaps)?
>
> This discussion has not yet pointed to an ARM rule that forbids gaps in 
> the array's representation.

There's no language rule of course, but more a practical one: operations 
like slicing and sliding become challenging if the array has gaps. And you 
don't get to ignore those just 'cause they're hard.

                      Randy.


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Problem with Position of the enumeration Type
  2019-01-23 21:42 ` Niklas Holsti
  2019-01-23 22:35   ` Simon Wright
@ 2019-01-26  9:44   ` G.B.
  1 sibling, 0 replies; 25+ messages in thread
From: G.B. @ 2019-01-26  9:44 UTC (permalink / raw)


On 23.01.19 22:42, Niklas Holsti wrote:
> 
> As others have also noted, enumeration representation clauses are used mostly when the enumeration value is an input (say, from some memory-mapped control register, or from a binary input file) or an output. Communication protocols and HW interfaces often define fields that encode some finite set of possible logical values/meanings, but where the encoding has gaps.
> 
> A final note: if you use an enumerated type for an input value, it is wise to check if the input is valid before using it. Use the 'Valid attribute for this. However, this attribute can also have a non-trivial cost. For example, the compiler may implement the function call E_Test'Valid(E) by code that compares the (representation of) E against each of the valid values 10, 21, 34, 100, 255 in turn (although a better compiler would use a binary search).

Has it been pointed out that one can use two enum types
together, one for I/O and the other for internal purposes
and then simply convert?

    type E_Test is (A, B, C);

    type E_for_IO is new E_Test;
    for E_for_IO use
       (A => 2#0000_1010#
        B => 2#0001_0101#
        C => 2#0010_0010#);

...

    some_E_Test := E_Test (some_E_for_IO);


-- 
"HOTDOGS ARE NOT BOOKMARKS"
Springfield Elementary teaching staff


^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2019-01-26  9:44 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-23 10:05 Problem with Position of the enumeration Type Luis Ladron de Guevara Moreno
2019-01-23 10:33 ` AdaMagica
2019-01-23 10:55   ` AdaMagica
2019-01-23 12:08   ` Luis Ladron de Guevara Moreno
2019-01-23 12:15     ` Karl Müller
2019-01-23 21:50     ` Niklas Holsti
2019-01-24  8:06     ` AdaMagica
2019-01-23 11:32 ` Mark Lorenzen
2019-01-23 12:30   ` Luis Ladron de Guevara Moreno
2019-01-23 20:22     ` Shark8
2019-01-24  8:13       ` AdaMagica
2019-01-23 17:06 ` Simon Wright
2019-01-23 22:54   ` Randy Brukardt
2019-01-23 23:47     ` Keith Thompson
2019-01-24  4:34       ` Keith Thompson
2019-01-24  9:11         ` Simon Wright
2019-01-24 21:41       ` Randy Brukardt
2019-01-23 21:42 ` Niklas Holsti
2019-01-23 22:35   ` Simon Wright
2019-01-23 23:20     ` Niklas Holsti
2019-01-24 16:43     ` Jeffrey R. Carter
2019-01-24 19:39       ` Niklas Holsti
2019-01-24 20:29         ` Jeffrey R. Carter
2019-01-24 21:43         ` Randy Brukardt
2019-01-26  9:44   ` G.B.

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox