Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2016-06

why (ClassType as TMyClass).Create fails

3 messages · 3 people ·

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Dennis

Following up to the cloning example code:

Type
  TMyClassRef = class of TMyClass;
implementation
function TMyClass.Clone(AOwner: TComponent): TMyClass;
begin
   Result := TMyClassRef(ClassType).Create(AOwner);
//but the next line will fail to compile
//  Result := (ClassType as TMyClassRef).Create(aOwner);
   Result.Assign(Self);
end

Isn't (ClassType as TMyClassRef).Create(aOwner) supposed to be safer because sometimes we copy and paste code around and in the end (ClassType might not be a descendant of TMyClass and the compiler won't catch this type mismatch if we do

   Result := TMyClassRef(ClassType).Create(AOwner);

Am I missing something?

Dennis

Michael Van Canneyt
to Dennis
Dennis wrote 13 lines
Following up to the cloning example code: Type TMyClassRef = class of TMyClass; implementation function TMyClass.Clone(AOwner: TComponent): TMyClass; begin Result := TMyClassRef(ClassType).Create(AOwner); //but the next line will fail to compile // Result := (ClassType as TMyClassRef).Create(aOwner);
This should be
   TMyClassRef(ClassType).Create(aOwner);
Show quoted text 11 lines
Result.Assign(Self); end Isn't (ClassType as TMyClassRef).Create(aOwner) supposed to be safer because sometimes we copy and paste code around and in the end (ClassType might not be a descendant of TMyClass and the compiler won't catch this type mismatch if we do Result := TMyClassRef(ClassType).Create(AOwner); Am I missing something?

No, this construct is not supported.

Michael.

Michalis Kamburelis
to Dennis: Following up to the cloning example code: Type TMyClassRef = class of TMyClass;…

2016-06-21 15:57 GMT+02:00 Dennis :

Show quoted text 25 lines
Following up to the cloning example code: Type TMyClassRef = class of TMyClass; implementation function TMyClass.Clone(AOwner: TComponent): TMyClass; begin Result := TMyClassRef(ClassType).Create(AOwner); //but the next line will fail to compile // Result := (ClassType as TMyClassRef).Create(aOwner); Result.Assign(Self); end Isn't (ClassType as TMyClassRef).Create(aOwner) supposed to be safer because sometimes we copy and paste code around and in the end (ClassType might not be a descendant of TMyClass and the compiler won't catch this type mismatch if we do Result := TMyClassRef(ClassType).Create(AOwner); Am I missing something?

The "is" / "as" operators are just not defined on class references (they only on classes and interfaces). Not really sure why.

To make the typecast *somewhat* safer (but see disclaimers below) you can check the InheritsFrom (
http://www.freepascal.org/docs-html/rtl/system/tobject.inheritsfrom.html ) before casting. InheritsFrom is a class method, it can be used on instances of class references easily.

So like

if ClassType.InheritsFrom(TMyClass) then
  Result := TMyClassRef(ClassType).Create(AOwner) else
  raise Exception.Create(...);

Note that you check for "InheritsFrom(TMyClass)" , not "InheritsFrom(TMyClassRef)". So it will *not* secure from bugs when someone changes the definition of TMyClassRef (to be "class of TSomeOtherClass").

But it will secure from bugs if this code is copy-pasted into some unrelated class, where ClassType is not compatible with TMyClass.

Actually, since this is inside an instance, you can write "InheritsFrom(TMyClass)" instead of
"ClassType.InheritsFrom(TMyClass)". Actually you can write "Self is TMyClass". Which is actually trivially true in this code (this is inside a TMyClass method)... But maybe some variation of this check will be useful, if this is used in a more complicated code, with something less obvious than "ClassType" as an argument.

Regards,
Michalis