Sign in Join

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

Mailing lists / fpc-pascal / 2010-03

constructor as procvar

9 messages · 6 people · –

Reply by email Subscribe to this list Your subscription

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

David Emerson

I'd like to pass a constructor as a procvar. Don't know if this is possible. Here is some silly illustrative code that doesn't work:

{$mode objfpc}
uses classes, sysutils;
type
  t_mammal = class
    public
      constructor create (color : byte); virtual;
    end;
  t_pig = class (t_mammal)
    // some fields, methods
    end;
  // the following fails:
  t_mammal_creator = t_mammal.constructor (color : byte) of object;
  // a list of animals...
  t_barnyard = class
    public
      function find_or_create_animal (color : byte;
          pass_create : t_mammal_creator) : t_mammal;
    end;
constructor t_mammal.create (color : byte);
  begin
  end;
function t_barnyard.find_or_create_animal (color : byte;
    pass_create : t_mammal_creator) : t_mammal;
  begin
    // look for the animal within the list. if not found:
    result := pass_create (color);
  end;
const
  brown = 18;
var
  pig_pen : t_barnyard;
  brown_pig : t_pig;
begin
  pig_pen := t_barnyard.create;
  brown_pig := t_pig (pig_pen.find_or_create_animal
      (brown, @t_pig.create));
end.

As you can (probably) see, I would like t_barnyard to be able to create any descendant of t_mammal. In the above example, I want it to create a brown pig if it doesn't find one, so I tried to pass the t_pig constructor, along with the brown parameter that said constructor will require. But I can't figure out the syntax. Perhaps this kind of thing is not supported?

Thanks!
~David.

Florian Klaempfl
to David Emerson
Show quoted text 6 lines
As you can (probably) see, I would like t_barnyard to be able to create any descendant of t_mammal. In the above example, I want it to create a brown pig if it doesn't find one, so I tried to pass the t_pig constructor, along with the brown parameter that said constructor will require. But I can't figure out the syntax. Perhaps this kind of thing is not supported?

Constructor procvars are indeed not supported but the way to achieve what you want is to use class type variables (untested, but it should illustrate the idea):

{$mode objfpc}
uses classes, sysutils;
type
  t_mammal = class
    public
      constructor create (color : byte); virtual;
    end;
  t_pig = class (t_mammal)
    // some fields, methods
    end;
  // the following fails:
  t_mammal_class = class of t_mammal;
  // a list of animals...
  t_barnyard = class
    public
      function find_or_create_animal (color : byte;
          mammal_creator : t_mammal_creator) : t_mammal;
    end;
constructor t_mammal.create (color : byte);
  begin
  end;
function t_barnyard.find_or_create_animal (color : byte;
    mammal_creator: t_mammal_creator) : t_mammal;
  begin
    // look for the animal within the list. if not found:
    result := mammal_creator.create(color);
  end;
const
  brown = 18;
var
  pig_pen : t_barnyard;
  brown_pig : t_pig;
begin
  pig_pen := t_barnyard.create;
  brown_pig := t_pig (pig_pen.find_or_create_animal
      (brown, t_pig));
end.
David Emerson
to Florian Klaempfl
Florian Klaempfl wrote 9 lines
Constructor procvars are indeed not supported but the way to achieve what you want is to use class type variables t_mammal_class = class of t_mammal;   function find_or_create_animal (color : byte;     pass_mammal_type : t_mammal_class) : t_mammal;   brown_pig := t_pig (pig_pen.find_or_create_animal (brown, t_pig));

ah, that is exactly what I need. Works perfectly. Thanks much.

~D.

David Emerson
to David Emerson

How can I obtain a class type variable from an instance? I want to create a second instance of the same descendant class (via the constructor, which will take some parameters and make the new instance unique)

Tobject.classtype returns TClass (class of TObject) which I first assumed would work great. However I cannot seem to do a type conversion from TClass to t_mammal_class (class of t_mammal)! So I am stuck here.

I tried just using TClass and skipping t_mammal_class, but then I can't use my overriden constructor that takes special parameters.

Thanks in advance,
David.

David Emerson wrote 19 lines
Florian Klaempfl wrote: > Constructor procvars are indeed not supported but the way to achieve > what you want is to use class type variables > > t_mammal_class = class of t_mammal; > > function find_or_create_animal (color : byte; > pass_mammal_type : t_mammal_class) : t_mammal; > > brown_pig := t_pig (pig_pen.find_or_create_animal (brown, t_pig)); ah, that is exactly what I need. Works perfectly. Thanks much. ~D. _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Marc Weustink
to David Emerson
David Emerson wrote 8 lines
How can I obtain a class type variable from an instance? I want to create a second instance of the same descendant class (via the constructor, which will take some parameters and make the new instance unique) Tobject.classtype returns TClass (class of TObject) which I first assumed would work great. However I cannot seem to do a type conversion from TClass to t_mammal_class (class of t_mammal)! So I am stuck here.

IIRC you can do t_mammal_class(my_mammal.ClassType).Create

Marc

Show quoted text 32 lines
I tried just using TClass and skipping t_mammal_class, but then I can't use my overriden constructor that takes special parameters. Thanks in advance, David. On Fri 19 Mar 2010, David Emerson wrote: > Florian Klaempfl wrote: >> Constructor procvars are indeed not supported but the way to achieve >> what you want is to use class type variables >> >> t_mammal_class = class of t_mammal; >> >> function find_or_create_animal (color : byte; >> pass_mammal_type : t_mammal_class) : t_mammal; >> >> brown_pig := t_pig (pig_pen.find_or_create_animal (brown, t_pig)); > ah, that is exactly what I need. Works perfectly. Thanks much. > > ~D. > > _______________________________________________ > fpc-pascal maillist - > http://lists.freepascal.org/mailman/listinfo/fpc-pascal > _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Andrew Hall
to David Emerson: How can I obtain a class type variable from an instance? I want to create a second…

Hi David,

If I'm reading your need correctly...

function CopyMyMammal(value: T_Mammal; extraParameters): T_Mammal;
begin
  result := T_Mammal_Class(value.ClassType).Create(withExtraParameters);
end;

Only confusion is you say you cannot make the type conversion? But the above code is correct and should compile... If you cannot make it work, please post the code that will not compile and the error you are getting.

Regards, Andrew.

David Emerson wrote 11 lines
How can I obtain a class type variable from an instance? I want to create a second instance of the same descendant class (via the constructor, which will take some parameters and make the new instance unique) Tobject.classtype returns TClass (class of TObject) which I first assumed would work great. However I cannot seem to do a type conversion from TClass to t_mammal_class (class of t_mammal)! So I am stuck here. I tried just using TClass and skipping t_mammal_class, but then I can't use my overriden constructor that takes special parameters.
Juha Manninen
to David Emerson: How can I obtain a class type variable from an instance? I want to create a second…

Hi

The essential part is to have virtual constructor like in Florian Klaempfl's example code:

  t_mammal = class
    public
      constructor create (color : byte); virtual;
    end;

and then...

  t_pig = class(t_mammal)
    public
      constructor create (color : byte); override;
    end;
t_mammal_class = class of t_mammal;

and later...

function create_mammal(m: t_mammal_class): t_mammal;
begin
  result := m.create(...);
end;

Without the virtual constructor it doesn't work.

Juha

Michael Van Canneyt
to David Emerson: How can I obtain a class type variable from an instance? I want to create a second…
David Emerson wrote
How can I obtain a class type variable from an instance? I want to create a second instance of the same descendant class (via the constructor, which will take some parameters and make the new instance unique)

Try using Instance.ClassType. Something like:

Var
   C : t_mammal_class;
   MyClone : T_mammal;
begin
   C:=t_mammal_class(Instance.ClassType);
   MyClone:=C.Create;
end;

Michael.

Show quoted text 37 lines
Tobject.classtype returns TClass (class of TObject) which I first assumed would work great. However I cannot seem to do a type conversion from TClass to t_mammal_class (class of t_mammal)! So I am stuck here. I tried just using TClass and skipping t_mammal_class, but then I can't use my overriden constructor that takes special parameters. Thanks in advance, David. On Fri 19 Mar 2010, David Emerson wrote: > Florian Klaempfl wrote: >> Constructor procvars are indeed not supported but the way to achieve >> what you want is to use class type variables >> >> t_mammal_class = class of t_mammal; >> >> function find_or_create_animal (color : byte; >> pass_mammal_type : t_mammal_class) : t_mammal; >> >> brown_pig := t_pig (pig_pen.find_or_create_animal (brown, t_pig)); > > ah, that is exactly what I need. Works perfectly. Thanks much. > > ~D. > > _______________________________________________ > fpc-pascal maillist - > http://lists.freepascal.org/mailman/listinfo/fpc-pascal > _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal