[fpc-devel] [Suggestion] Enumeration range-check intrinsic

Michael Van Canneyt michael at freepascal.org
Fri Jul 5 09:04:44 CEST 2019



On Fri, 5 Jul 2019, J. Gareth Moreton wrote:

> Please don't put words in my mouth Michael or twist me up with word 
> play.  I have never said I want to forbid the storing or communication 
> of enumerations, and if people start using my argument for the exact 
> opposite of what I'm trying to advocate and smugly say "I rest my case", 
> then you can have my resignation. Please clarify with me before making 
> such assumptions next time.

My aplogies. I didn't mean to put words in your mouth, I really understood
your argument as a case for not using enumerations in most cases.

It seems I misunderstood you.

>
> My original suggestion was to use an intrinsic like "if 
> IsValidEnum(Value) then" as an efficient and robust way to check if the 
> variable contains a valid value for the relevant enumeration, once which 
> won't be shortcut by the compiler's assumptions as with case blocks and 
> the if-statement in the last paragraph.  It was then brought to my 
> attention that a variant had already been proposed with the "is" 
> operator, which in my eyes is a little bit better because it doesn't 
> introduce a new intrinsic that may clash with existing function names in 
> some projects.

My thinking exactly. With the exception that the construct must be used on
the integer value instead of the enumerated, as the enumerated is expected
to have valid values only, and the check must be done before converting.


> But to avoid a fight or anything of the sort, given that external data 
> is read as an enumeration and may contain invalid data (which to give a 
> concrete definition, is an integer value that doesn't map to any element 
> in the enumeration), and it won't be caught by case blocks and can 
> trigger an access violation if a jump table is employed (this is how the 
> compiler currently behaves), what would you propose be the best solution?


Well, I still favour:

Type
   TMyEnum = (one, two, three);

Var
   I : Integer;
   M : TMyEnum;

begin
   I:=0;
   if I is TMyEnum then
     M:=TMyEnum(I); // Will be executed
   I:=3;
   if I is TMyEnum then
     M:=TMyEnum(I); // Will NOT be executed
   // and
   I:=0;
   M:=I as TMyEnum; // Will work
   I:=3;
   M:=I as TMyEnum; // Will raise out of range run-time error
end.

IMO, if the compiler insists on assuming that an enumerated value contains
only valid values (an assumption I endorse, as it allows better optimization) 
then it should also give the programmer the means of easily assuring this,
because the language also allows for many cases where the assumption may be
invalid: typecasts, variant records.

I think the above proposal does exactly that.

In this, I would definitely exclude enumerateds that have explicitly assigned
values: str does not handle them, getenumename etc. also do not work:
They are in effect simply integer constants. (if I had my way I would
even remove them from the language).

So using the above construct on such an enum can lead to a compiler error,
because the compiler cannot check anyway: better a clear error than undefined
behaviour.

Michael.


More information about the fpc-devel mailing list