I see your point. There seems to be some argument because it
effectively bans the use of enumerations in external data (e.g. a file,
network packet or third-party API) if there's a chance that the value is
corrupted or has been tampered with, because sometimes allowing the
program to crash is not acceptable. Though misinterpreted, Michael said
this to me when I mentioned to the effect of "in that case, you could
only use Integers etc. for external data":
...
With this sentence you forbid storing or communicating enumerated values
in any way: file, database, over network. It can be used only in a
computer program and never
leave the context of the running program under any form. Because as soon as
it is somehow communicated, there is a chance it becomes invalid in return
communication.
Additionally you must then also abolish typecasting to an enumerated (or
pointers to enumerated values), since that also can be a source of invalid
values for an enumerated.
Or are you realy advocating we write code such as
Case MyInteger of
0 : MyEnum:=ValueOrd0
1 : MyEnum:=ValueOrd2;
else
someError
end;
etc, whenever an integer must be changed to an enumerated ?
IMHO you would reduce the usabilty of enumerateds to almost zero by doing
so.
...
Here lies the problem - if you have a enumeration stored in a byte
field, say, in a file, and there's a chance it's been corrupted, there's
no reliable way to detect that, since even typecasting may not be
reliable, and once again I'm implying that enums are unsafe to use, but
right now, what else can one do?
Gareth aka. Kit
On 13/07/2019 12:28, Martin Frb wrote:
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
---
This email has been checked for viruses by Avast antivirus software.
https://www.avast.com/antivirus
_______________________________________________
fpc-devel maillist - fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel