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

_______________________________________________
fpc-devel maillist  -  fpc-devel@lists.freepascal.org
https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-devel

Reply via email to