[fpc-devel] [Suggestion] Enumeration range-check intrinsic
Ondrej Pokorny
lazarus at kluug.net
Wed Jul 3 01:38:38 CEST 2019
On 02.07.2019 23:34, Jonas Maebe wrote:
> On 02/07/2019 22:31, Ondrej Pokorny wrote:
>> This is similar to the object-is operator that gets evaluated as well
>> even if the type of the left-side value is the type at right side:
>>
>> var
>> Value: TPersistent;
>> begin
>> Value := TPersistent(TObject.Create);
>> IsValid := Value is TPersistent; // IsValid gains false
> This is an invalid program. If you compile with -CR, the program will
> abort with an error when the typecast is performed, because it will get
> replaced by an "as" operation. In that sense, "integer as enum" would
> indeed be somewhat similar, and -CR might even be extended to perform
> the same replacement of explicit typecasts with "as" operators for these
> types.
No, this is a perfectly valid program with a perfectly defined behavior!
It is a perfectly valid program even with -CR. When I use -CR I expect
an exception and I will handle it - in this case I don't need the is-check:
var
Value: TPersistent;
begin
try
Value := TPersistent(TObject.Create); // or: TObject.Create as
TPersistent (without -CR)
except
Writeln('Wrong value supplied! Exit.');
Exit;
end;
// do something
Readln;
end.
A good real-word example is the cast from a pointer:
program Project1;
uses Classes;
var
Value: TPersistent;
P: Pointer;
begin
P := TObject.Create;
Value := TPersistent(P);
if Value is TPersistent then
Writeln('Value is TPersistent')
else
Writeln('Value is not TPersistent');
Readln;
end.
> As an example of an operation on the resulting "Value" that is already
> undefined: if you would call a TPersistent virtual method on it, and
> whole-program optimization devirtualised that call, it may call the
> "correct" method of TPersistent instead of using the VMT of whatever
> other class instance type Value points to.
Yes, I agree that calling an (unavailable) method on an object casted to
a wrong class is an invalid operation. But this is not what I did in my
example. Preventing calls of unavailable methods or access of
unavailable fields is exactly what I the IS-operator is for.
> Invalid data means undefined behaviour, always. "is" is not a special
> case that is immune to this.
We are again at the very fundamental question "what invalid data is".
Storing a TObject in TPersistent is not an invalid operation IMO. Both
are class objects and both can be checked for inheritance with the
IS-operator. Calling methods, accessing fields etc. on the TObject-value
in TPersistent-variable is invalid, indeed. But not a simple IS-operator.
What I understand as invalid for the IS-operator is e.g. trying to call
it for an interface in TPersistent variable:
var
Value: TPersistent;
P: Pointer;
I: IUnknown;
begin
I := TInterfacedObject.Create;
P := I;
Value := TPersistent(P);
if Value is TPersistent then
> And e.g. in the context of generics,
> simplifying/removing such checks where possible would probably be quite
> desirable.
Not really. The IS-operator returns false for NIL that is a valid value,
so you cannot remove such checks:
var
Value: TPersistent;
IsValid: Boolean;
begin
Value := nil;
IsValid := Value is TPersistent; // IsValid gains false - you cannot
simply replace this check with true
Writeln(IsValid);
Readln;
end.
Ondrej
More information about the fpc-devel
mailing list