Sign in Join

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

Mailing lists / fpc-pascal / 2011-11

Class reference doubt

11 messages · 5 people · –

Reply by email Subscribe to this list Your subscription

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

Jesus Reyes

in the following example The output is:
cls class is TFoo
TObj.create

where I would expect:
cls class is TFoo
TObj.create
TFoo.create

ie the TFoo.constructor is not called, is this normal/expected?, The documentation does clarify the situation: http://www.freepascal.org/docs-html/ref/refse31.html

"Class reference types are used to create instances of a certain class, which is not yet known at compile time, but which is specified at run time. Essentially, a variable of a class reference type contains a pointer to the definition of the speficied class. This can be used to construct an instance of the class corresponding to the definition, or to check inheritance."

Thanks.

Jesus Reyes A.

program test;
{$mode ObjFpc}{$H+}
type
  TObj = class
  public
    constructor create;
  end;
  TObjClass=class of TObj;
  TFoo = class(TObj)
  public
    constructor create;
  end;
constructor TObj.Create;
begin
  inherited create;
  WriteLn('TObj.create');
end;
constructor TFoo.create;
begin
  inherited Create;
  WriteLn('TFoo.Create');
end;
var
  cls: TObjClass;
  obj: TObj;
begin
  cls := TFoo;
  WriteLn('cls class is ',cls.ClassName);
  Obj := cls.Create;
  Obj.Free;
end.
Jonas Maebe
to Jesus Reyes
Jesus Reyes wrote 10 lines
in the following example The output is: cls class is TFoo TObj.create where I would expect: cls class is TFoo TObj.create TFoo.create ie the TFoo.constructor is not called, is this normal/expected?

Yes. You have to use a virtual constructor if you wish to override in a child class, just like with regular methods and class methods.

Jonas

Luiz Americo Pereira Camara
to Jesus Reyes: in the following example The output is: cls class is TFoo TObj.create where I would…
Jesus Reyes wrote 8 lines
in the following example The output is: cls class is TFoo TObj.create where I would expect: cls class is TFoo TObj.create TFoo.create

I also hit this problem recently

Found that this is one limitation of fpc. Under newer delphi it's possible to get the expected behavior without forcing programmer to create a virtual constructor by using the new RTTI

Luiz

Graeme Geldenhuys
to Luiz Americo Pereira Camara
Luiz Americo Pereira Camara wrote
possible to get the expected behavior without forcing programmer to create a virtual constructor by using the new RTTI

What has the "new RTTI" got to do with anything?

Simply define TObj.Create as virtual, and TFoo.Create as overridden. This is rather normal coding practise with classes. Nothing special.

----8<-------------8<-------------8<-------------8<-------------8<----
program test;
{$mode ObjFpc}{$H+}
type
  TObj = class
  public
    constructor create; virtual;
  end;
  TObjClass=class of TObj;
  TFoo = class(TObj)
  public
    constructor create; override;
  end;
constructor TObj.Create;
begin
  inherited create;
  WriteLn('TObj.create');
end;
constructor TFoo.create;
begin
  inherited Create;
  WriteLn('TFoo.Create');
end;
var
  cls: TObjClass;
  obj: TObj;
begin
  cls := TFoo;
  WriteLn('cls class is ',cls.ClassName);
  Obj := cls.Create;
  Obj.Free;
end.
----8<-------------8<-------------8<-------------8<-------------8<----

And here is the output...

$ ./test
cls class is TFoo
TObj.create
TFoo.Create

Regards,
- Graeme -

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/
Jonas Maebe
to Luiz Americo Pereira Camara: I also hit this problem recently Found that this is one limitation of fpc. Under newer…
Luiz Americo Pereira Camara wrote 15 lines
On 23/11/2011 18:48, Jesus Reyes wrote: > in the following example The output is: > cls class is TFoo > TObj.create > > where I would expect: > cls class is TFoo > TObj.create > TFoo.create I also hit this problem recently Found that this is one limitation of fpc. Under newer delphi it's possible to get the expected behavior without forcing programmer to create a virtual constructor by using the new RTTI

I find it very hard to believe that the behaviour of existing code like that would suddenly change (and hence potentially break programs) simply because extra RTTI is added.

Jonas

Luiz Americo Pereira Camara
to Jonas Maebe
Jonas Maebe wrote 22 lines
On 24 Nov 2011, at 02:58, Luiz Americo Pereira Camara wrote: > On 23/11/2011 18:48, Jesus Reyes wrote: >> in the following example The output is: >> cls class is TFoo >> TObj.create >> >> where I would expect: >> cls class is TFoo >> TObj.create >> TFoo.create > > I also hit this problem recently > > Found that this is one limitation of fpc. Under newer delphi it's > possible to get the expected behavior without forcing programmer to > create a virtual constructor by using the new RTTI I find it very hard to believe that the behaviour of existing code like that would suddenly change (and hence potentially break programs) simply because extra RTTI is added.

It does not change. The task is accomplished by other means

See
http://code.google.com/p/emballo/source/browse/trunk/Src/Emballo.DI.Instantiator.pas#152

Luiz

Luiz Americo Pereira Camara
to Graeme Geldenhuys: What has the "new RTTI" got to do with anything? Simply define TObj.Create as virtual,…
Graeme Geldenhuys wrote 7 lines
On 2011-11-24 03:58, Luiz Americo Pereira Camara wrote: > possible to get the expected behavior without forcing programmer to > create a virtual constructor by using the new RTTI What has the "new RTTI" got to do with anything? Simply define TObj.Create as virtual, and TFoo.Create as overridden. This is rather normal coding practise with classes. Nothing special.

This solution is not quite generic because is necessary to descend from an specific class and also needs to change an interface declaration. So to use in old code / classes it would be necessary to change the hierarchy and the interface.

Also it would not work with classes that i cant change the hierarchy like rtl ones or third party

With Delphi is possible to call a constructor even if has a different name from Create and with parameters without changing interface or hierarchy

It seems useful for me

Luiz

Show quoted text 52 lines
----8<-------------8<-------------8<-------------8<-------------8<---- program test; {$mode ObjFpc}{$H+} type TObj = class public constructor create; virtual; end; TObjClass=class of TObj; TFoo = class(TObj) public constructor create; override; end; constructor TObj.Create; begin inherited create; WriteLn('TObj.create'); end; constructor TFoo.create; begin inherited Create; WriteLn('TFoo.Create'); end; var cls: TObjClass; obj: TObj; begin cls := TFoo; WriteLn('cls class is ',cls.ClassName); Obj := cls.Create; Obj.Free; end. ----8<-------------8<-------------8<-------------8<-------------8<---- And here is the output... $ ./test cls class is TFoo TObj.create TFoo.Create Regards, - Graeme -
Jonas Maebe
to Luiz Americo Pereira Camara: It does not change. The task is accomplished by other means See…
Luiz Americo Pereira Camara wrote 17 lines
On 24/11/2011 08:02, Jonas Maebe wrote: > > On 24 Nov 2011, at 02:58, Luiz Americo Pereira Camara wrote: > >> On 23/11/2011 18:48, Jesus Reyes wrote: >>> where I would expect: >>> cls class is TFoo >>> TObj.create >>> TFoo.create >> >> I also hit this problem recently >> >> Found that this is one limitation of fpc. Under newer delphi it's possible to get the expected behavior without forcing programmer to create a virtual constructor by using the new RTTI > > I find it very hard to believe that the behaviour of existing code like that would suddenly change (and hence potentially break programs) simply because extra RTTI is added. It does not change.

In that case, you did not hit the same problem as the original poster (your "I also hit this problem recently" is what triggered my response). His problem was that if you call a non-virtual constructor on a class reference variable, that the constructor is determined based on the static type of the class reference rather than on the dynamic type.

That's indeed a completely different technique to dynamically instantiate classes (and if you don't really need that kind of flexibility, I would recommend virtual constructors instead since they're much simpler and faster).

Jonas

Luiz Americo Pereira Camara
to Jonas Maebe
Jonas Maebe wrote
In that case, you did not hit the same problem as the original poster (your "I also hit this problem recently" is what triggered my response). His problem was that if you call a non-virtual constructor on a class reference variable, that the constructor is determined based on the static type of the class reference rather than on the dynamic type.

It does not matter much but i hit the same problem. Just replace class of TObj by class of TObject (TClass)

I stored a class (TMyClass) in a class variable (AClass: TClass). I was expecting that calling AClass.Create would call TMyClass.Create. Just like him i found that is not the case.

To be clear: i'm not saying that is a bug or asking for changing the behavior

> The task is accomplished by other means > > See http://code.google.com/p/emballo/source/browse/trunk/Src/Emballo.DI.Instantiator.pas#152 That's indeed a completely different technique to dynamically instantiate classes (and if you don't really need that kind of flexibility, I would recommend virtual constructors instead since they're much simpler and faster).

I will do in a third way, that keeps flexibility (and is also fast) but requires more typing.

Luiz

Dimitri Smits
----- "Luiz Americo Pereira Camara" wrote 21 lines
On 24/11/2011 19:34, Jonas Maebe wrote: > In that case, you did not hit the same problem as the original poster (your "I also hit this problem recently" is what triggered my response). His problem was that if you call a non-virtual constructor on a class reference variable, that the constructor is determined based on the static type of the class reference rather than on the dynamic type. It does not matter much but i hit the same problem. Just replace class of TObj by class of TObject (TClass) I stored a class (TMyClass) in a class variable (AClass: TClass). I was expecting that calling AClass.Create would call TMyClass.Create. Just like him i found that is not the case. To be clear: i'm not saying that is a bug or asking for changing the behavior

so you have:
====
type
TMyObject=class(TObject)
...

   constructor Create;
  end;
  TMyClass = class of TMyObject; // <-- important I guess

...

procedure processSomething(AClass: TClass);
var
  someInstance: TObject;
begin
  someInstance := AClass.Create(); // <-- always the one from TClass/TObject?
end;
...
begin
  processSomething(TMyObject);
end;

====

class methods (and the constructors and destructor) are in Delphi part of the TClass memorystructure. I believe even the TObject default Create. For your trick to work, you need one of 2 things:
- declare the class-reference for a type explicitly (class of T...)
- make a virtual constructor in a subtype of TObject and declare a class-reference. Then you derive from that subtype.

I don't think (did not test) it finds a TMyClass in Delphi as well if you do not declare the type, so in effect it always takes TClass. The other scenario's I've used before in classfactory pattern before.

It has nothing and everything to do with RTTI. No, the new D2010+ RTTI does not give access to the default constructor (I think), but it IS part of the TClass-alike-structure that is generated for the TObject descendant.

kind regards,
Dimitri Smits

Luiz Americo Pereira Camara
to Dimitri Smits
Dimitri Smits wrote 8 lines
so you have: ==== type TMyObject=class(TObject) ... constructor Create; end;

Yes

TMyClass = class of TMyObject; //<-- important I guess

Not important or necessary. I was using TClass from RTL = class of TObject

Show quoted text 9 lines
... procedure processSomething(AClass: TClass); var someInstance: TObject; begin someInstance := AClass.Create(); //<-- always the one from TClass/TObject? end;

Yes

Show quoted text 10 lines
... begin processSomething(TMyObject); end; ==== class methods (and the constructors and destructor) are in Delphi part of the TClass memorystructure. I believe even the TObject default Create. For your trick to work, you need one of 2 things: - declare the class-reference for a type explicitly (class of T...) - make a virtual constructor in a subtype of TObject and declare a class-reference. Then you derive from that subtype.

I know all of this. I even already use this approach in one of my libraries where i have a base class and a reference to class of this type.

What i needed this time was more generic: the ability to instantiate any TObject without the need to change interface of the classes

I don't think (did not test) it finds a TMyClass in Delphi as well if you do not declare the type, so in effect it always takes TClass. The other scenario's I've used before in classfactory pattern before. It has nothing and everything to do with RTTI. No, the new D2010+ RTTI does not give access to the default constructor (I think),

Yes, it does see example at
http://code.google.com/p/emballo/source/browse/trunk/Src/Emballo.DI.Instantiator.pas#152

Anyway, i already found a solution, so there's no fuzz in my part

Luiz