Creating "TEdit" component dynamically lazarus / 31-LCL ---------------------------------------------------------------------- pascal111 · 2021-05-05 11:48 I'm trying to create "TEdit" component dynamically, but I see no result. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  var  Form1: TForm1;  e1:tedit; procedure TForm1.FormCreate(Sender: TObject);begin   e1:=tedit.Create(self);   e1.Height:=28;  e1.Width:=127;  e1.Left:=95;  e1.Top:=56;   e1.Text:='Hello World!'; end; procedure TForm1.FormDestroy(Sender: TObject);begin  e1.Free;end; ---------------------------------------------------------------------- dseligo · 2021-05-05 11:51 You didn't set parent: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i e1.Parent:=Self; ---------------------------------------------------------------------- pascal111 · 2021-05-05 12:11 It works! Thanks! ---------------------------------------------------------------------- alpine · 2021-05-05 12:19 One more thing, since you gave an Owner to the TEdit by: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i e1:=tedit.Create(self); You shall not free it at FormDestroy(). It will be freed by the Owner at the right time. ---------------------------------------------------------------------- pascal111 · 2021-05-05 12:23 I got it! thanks! ---------------------------------------------------------------------- pascal111 · 2021-05-05 12:24 By the way, is there a problem if I said: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  e1.create(self); // rather than     e1:=tedit.Create(self); ---------------------------------------------------------------------- alpine · 2021-05-05 12:39 Quote from: pascal111 on May 05, 2021, 02:24:33 pmBy the way, is there a problem if I said: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i e1.create(self); // rather than     e1:=tedit.Create(self); It is not the same. The constructor is part of the class(TEdit), not the instance (e1). e1 is just a pointer internally. ---------------------------------------------------------------------- lucamar · 2021-05-05 12:55 Quote from: pascal111 on May 05, 2021, 02:24:33 pmBy the way, is there a problem if I said: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i e1.create(self); // rather than     e1:=tedit.Create(self); When you do that what you're doing is basically just calling a method of the instance, rather than invoking the constructor of the class. Two very different concepts. ---------------------------------------------------------------------- pascal111 · 2021-05-05 12:59 I see now. I think the different between the two concepts can be used in advanced uses of components. ---------------------------------------------------------------------- lucamar · 2021-05-05 13:08 Beyond the instance creation "magic", the constructor is sometimes used to initialize some fields, set some default properties, etc. If you're going to call it as a method to "reset" it to the default state it's usually better to include all those initializations to their own method (SetDefaults() or whatever) and call that instead. That way it's less confusing and there is no doubt about whether you're constructing the object or just "resetting" it. IMHO, of course ---------------------------------------------------------------------- pascal111 · 2021-05-05 13:16 It seems Lazarus freePascal is strong language in event driven programming, it cares in details, small things of OOP and Visual Programming and different techniques. ---------------------------------------------------------------------- alpine · 2021-05-05 16:38 Quote from: pascal111 on May 05, 2021, 02:59:06 pmI see now. I think the different between the two concepts can be used in advanced uses of components. It is quite simple actually, you may think of objects as of instances of a certain class, and for that class as of the only instance of some hypothetical meta-class. Therefore, all that is valid for the object can be applied to the class - the class also have its methods and data fields (static ones). So, the constructors are actually methods of the class - they construct an instance of the object and return them back as a reference: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   e1 := TEdit.Create(Self);  Means "call the method Create on (sole) instance of Meta-TEdit named TEdit and assign the returned reference to the e1".  As lucamar said, the: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   e1.Create(Self);  means "call the method Create on instance of TEdit named e1", but e1 doesn't exist yet and also does not have such a method. It's simple. ---------------------------------------------------------------------- pascal111 · 2021-05-05 16:42 It has logical sense @y.ivanov. I understand. ---------------------------------------------------------------------- Remy Lebeau · 2021-05-05 22:30 Quote from: y.ivanov on May 05, 2021, 02:19:50 pmOne more thing, since you gave an Owner to the TEdit by: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i e1:=tedit.Create(self); You shall not free it at FormDestroy(). It will be freed by the Owner at the right time. While it is true that an Owner will free the component automatically, it should be noted that it is perfectly safe to manually Free() a component that has an Owner assigned.  The component will simply remove itself from the Owner's internal list so that the Owner will not try to free the component again when the Owner is freed. ---------------------------------------------------------------------- alpine · 2021-05-06 00:43 Quote from: Remy Lebeau on May 06, 2021, 12:30:13 am*snip* While it is true that an Owner will free the component automatically, it should be noted that it is perfectly safe to manually Free() a component that has an Owner assigned.  The component will simply remove itself from the Owner's internal list so that the Owner will not try to free the component again when the Owner is freed. Formally true. My wording must be read "You may not free it" instead of "You shall not free it" then. On the other hand, giving a non-nil owner to a component on its constructor means that we're transferring the life-cycle management to that owner. If we intend to manage the component life-cycle by ourselves, it is much better to create it without owner. Mixing the two approaches will result in UAF sooner or later. ---------------------------------------------------------------------- lucamar · 2021-05-06 04:15 Quote from: y.ivanov on May 06, 2021, 02:43:28 amOn the other hand, giving a non-nil owner to a component on its constructor means that we're transferring the life-cycle management to that owner. Not always. For example imagine, if you will, you're creating a series of anonimous temporary controls and, for whatever reason, you don't want to create the tipical list to contain them. Giving them an Owner means that they will be locatable through the owner's Components "array" without necessarily meaning you want that owner to be responsible for them. ---------------------------------------------------------------------- alpine · 2021-05-06 11:04 Quote from: y.ivanov on May 06, 2021, 02:43:28 amFormally true. My wording must be read "You may not free it" instead of "You shall not free it" then. I have already admitted my incorrect statement. In practice, there can be many different cases that an experienced programmer knows how to handle. Generally, the life cycle management is something that must be taken most responsibly. I'm still thinking that mixing approaches is the sloped road to UAF. After all, even experienced programmers are not immune to it. ---------------------------------------------------------------------- PascalDragon · 2021-05-06 13:37 Quote from: y.ivanov on May 05, 2021, 06:38:00 pmAs lucamar said, the: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   e1.Create(Self);  means "call the method Create on instance of TEdit named e1", but e1 doesn't exist yet and also does not have such a method. To be fair it's perfectly fine to call a constructor as a normal method. The creation “magic” only exists when called using a class type. This also means if you have a constructor that doesn't access any of the fields, then that will work without problems on an invalid instance (as with any method) and the problems will only occur later, because the instance wasn't created (been there, done that ). ---------------------------------------------------------------------- alpine · 2021-05-06 15:15 To be honest, I suspected something like that (but how else to present this to a rookie). I'm curious about the realization, because, unlike C++, here the instances are purely dynamic and must be created explicitly. From what you say, I conclude that "magic" is the allocation on the heap and it only happens if it is called through the class. Otherwise, the constructor is called with an invalid Self as a regular method, is that correct? Isn't it forbidden from the compiler? I have never tried it... ---------------------------------------------------------------------- lucamar · 2021-05-06 16:54 Quote from: y.ivanov on May 06, 2021, 05:15:23 pmOtherwise, the constructor is called with an invalid Self as a regular method, is that correct? Isn't it forbidden from the compiler? I have never tried it... Yes, if the object hasn't been created normally then it's called with an invalid Self. It's not forbidden because there might be legitimate reasons to call it through an instance as a normal method (e.g. to "reset" the object to its default state). Quote from: PascalDragon on May 06, 2021, 03:37:08 pm(been there, done that ). As, I guess, most of us when coding in a hurry and not thinking clearly: "Oh, I forgot to create that string list! Let's see: MyStrings.Create; ..." ---------------------------------------------------------------------- alpine · 2021-05-06 17:53 Quote from: lucamar on May 06, 2021, 06:54:46 pm*snip* Yes, if the object hasn't been created normally then it's called with an invalid Self. It's not forbidden because there might be legitimate reasons to call it through an instance as a normal method (e.g. to "reset" the object to its default state). *snip* After reading few articles now I see it clearly! We use it all the time in the constructors (inherited Create;). Makes me think that the usual heap allocation can be skipped (e.g. for tiny embedded) and have a 'static' instances, something like: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var  Buf: array [0..MaxBuf-1] of Byte;  Mark: Integer;  O1, O2: TMyObject;begin   Mark := 0;   O1 := TMyObject(@Buf[Mark]); Mark := Mark + TMyObject.InstanceSize;   O1.Create;   O2 := TMyObject(@Buf[Mark]); Mark := Mark + TMyObject.InstanceSize;   O2.Create;   // etc.   MainProc;end.  Of course that kind of objects should never be Free'd. BTW, using obj.Create for resetting is considered a very dangerous practice. ---------------------------------------------------------------------- lucamar · 2021-05-06 18:00 Quote from: y.ivanov on May 06, 2021, 07:53:44 pmBTW, using obj.Create for resetting is considered a very dangerous practice. Thence my previous advice ---------------------------------------------------------------------- alpine · 2021-05-06 18:08 Quote from: lucamar on May 06, 2021, 08:00:04 pmThence my previous advice Absolutely right! Sorry, little dizzy of my (personal) findings. BTW, Is there a way to know InstanceSize at compile time? Something like SizeOf()? ---------------------------------------------------------------------- lucamar · 2021-05-06 19:13 Quote from: y.ivanov on May 06, 2021, 08:08:14 pmBTW, Is there a way to know InstanceSize at compile time? Something like SizeOf()? Not that I know of, sorry. If I may ask, why do you want it? For most classes InstanceSize is only a "lower estimation". ---------------------------------------------------------------------- alpine · 2021-05-06 19:36 Quote from: lucamar on May 06, 2021, 09:13:44 pm Not that I know of, sorry. If I may ask, why do you want it? For most classes InstanceSize is only a "lower estimation". For specifying the upper bound of the pre-allocated buffer in https://forum.lazarus.freepascal.org/index.php/topic,54470.msg404786.h tml#msg404786