On 11/07/2019 15:46, J. Gareth Moreton wrote:

For my personal point of view, I would like these operators to be the exception to the rule of the compiler assuming an enum always contains a valid value,

As much as I would like to agree with you (and yes I think such a check, if possible, would be desirable - even if it meant to ignore certain language design principles), it is indeed not possible. Maybe it would be today (as in today's fpc implementation), maybe not. I do not know.

But it would not be future safe.

Lets say "fpc breaks the rule for "is/as" and only for those".

  FooEnum := SomeApi();
  if not (FooEnum is TFooEnum) then FooEnum := low(TFooEnum);

Now we do *not* know what the optimizer does in the first line. And that is the problem. On some platform (that we have no clue of today), the compiler may store the value bitpacked into a temp var/register. The storage is shared with other values. If the result of "SomeApi()" is out of bounds, it might overwrite one of the other values stored in that var/register. The "is" can only check the part of the storage actually meant to be used by the enum. The change to the other value goes unnoticed.

So in such a future case, the is may do what you expect. A later "case FooEnum" will be ok, as FooEnum is "forced" to be valid. But your program still crashes, due to the other var being modified unexpectedly.

Yes that may sound far fetched. But maybe some embedded system, with scarce resources requires such behaviour?

----------------
Maybe a possible solution would be based on:

On 13/07/2019 12:48, Jonas Maebe wrote:
In Delphi's type system (and in C, C++, and C#), the valid values for an enum are always all values that fit within its storage size, and that storage size is fixed.

Create such an enum type in fpc too (as a new type / assignment compatible with the current enum)

  {modeswitch StorageSizeValidEnum}
  type TFullFooEnum = (a,b,c);

would treat all values of the (unpacked) storage as valid.
As a consequence:
 - it can not be packed / it would keep its full size
 - many optimizations can not be applied

But for such a type, that has explicitly been defined as having all the other values, you could use "is". Of course not straight forward. Because now  255 is a valid value for that enum, so "is" would return true. But with:

  {modeswitch StorageSizeValidEnum on}
  type TFullFooEnum = (a,b,c);
  {modeswitch StorageSizeValidEnum off}
  type TFooEnum = (a,b,c);

this would work:
  if  FullFooEnum is TFooEnum then

Since this is only/mainly used for "external" data, the extra type def would not be to much overhead.

Of course, it is merely syntactical sugar, since it is identical too
  type TFullFooEnum = integer; //or whatever represents the storage size
  type TFooEnum = (a,b,c);

It only allows to have named values for that "integer"
_______________________________________________
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply via email to