Jump to content

Dalija Prasnikar

Members
  • Content Count

    729
  • Joined

  • Last visited

  • Days Won

    63

Everything posted by Dalija Prasnikar

  1. Dalija Prasnikar

    Flash when showing form with VCL Styles

    Flicker in VCL Styles can have many root causes depending on the controls used and their settings. It is hard to tell what exactly causes it here and how to fix it. It seems like here it is caused by a form (or whatever control you have as a main container) clearing its canvas with white (default) color before painting dark style. First step would be to check all combinations of various settings on both form and other controls (especially if you have another container control that host other controls) (you may want to create simple test project for that) like ParentBackground, DoubleBuffering,... Also setting explicit background color to the dark one could help but that would also require adjusting StyleElements and removing seClient from them. If that does not work then another way would be to start playing with WM_ERASEBKGND messages in a container control (frame or panel) that is not styled. Fix mentioned in RSP-24415 has some issues on Windows 11 and non styled controls like combo boxes (I haven't tested with styled ones) that are not properly refreshed and they need their repainting and erasing tweaked. It is possible that you will be able to find some satisfactory fix by simple property changes and figuring out proper combination for that form, but it is also possible that fix would require more complicated hacks.
  2. Dalija Prasnikar

    I solved my problem but

    Right... my brain is fried...
  3. Dalija Prasnikar

    I solved my problem but

    This code is not 100% correct, though. If constructor fails, Free will be called on an uninitialized reference. In order for it to work properly, IdHTTP should be initialized to nil before calling constructor. begin IdHTTP := nil; IdHTTP := TIdHTTP.Create(nil); ... Edit... forget about that.... brain fart... if the exception is raised IdHTTP.Free will never be called.
  4. Dalija Prasnikar

    Custom Component : onDestroy delphi creates endless error messages

    Weak references are integral part of ARC as memory management system. Because ARC was not main memory management system in classic compiler and was just an "add on", most code didn't require them or could use pointers that are equivalent of unsafe attribute. Support for weak references in classic compiler was added only after they were added on mobile ARC compiler which requires weak references in order to have functional memory management system. Proper coding pattern for ARC memory management would indeed require using weak attribute in the similar circumstances (code) OP had. In other words, if we would rewrite RTL and VCL to follow ARC rules then the OP original code would be the correct one, and we would not need nor have TComponent notification system.
  5. Dalija Prasnikar

    Custom Component : onDestroy delphi creates endless error messages

    Weak attribute only works on interface references, not on object references. In your case, with TComponent reference, compiler just ignores weak attribute.
  6. Dalija Prasnikar

    Interfaces - Time to face my ignorance.

    If you are having trouble managing objects memory, then using interfaces is a bad option as using them requires even more knowledge. Yes, they can manage memory for you, but there is so much fine print attached I wouldn't recommend it as a starting point. Your drawing object list class also has some unnecessary code as it inherits from generic TObjectList that already automatically handles all that. I have simplified your code and added some basic workflow. uses System.Generics.Collections; type TDrawingObjectType = (doChild, doBackground); TDrawingObjectsList = class; //Forward Declaration TDrawingObject = class private FObjectType: TDrawingObjectType; FDrawingObjectsList: TDrawingObjectsList; public constructor Create(AObjectType: TDrawingObjectType); destructor Destroy; override; property ObjectType: TDrawingObjectType read FObjectType write FObjectType; property DrawingObjectsList: TDrawingObjectsList read FDrawingObjectsList; end; TDrawingObjectsList = class(TObjectList<TDrawingObject>) public procedure DrawDraw(ACanvas: IskCanvas); procedure LoadDrawingObjects; end; procedure BuildList(List: TDrawingObjectsList); var Root: TDrawingObject; implementation constructor TDrawingObject.Create(AObjectType: TDrawingObjectType); begin FDrawingObjectsList := TDrawingObjectsList.Create(True); end; destructor TDrawingObject.Destroy; begin FDrawingObjectsList.Free; inherited; end; procedure BuildList(List: TDrawingObjectsList); var Item: TDrawingObject; begin List.Clear; // build list Item := TDrawingObject.Create(doChild); // set Item data // ... // Add Item to List List.Add(Item); Item := TDrawingObject.Create(doChild); // set Item data // ... // Add Item to List List.Add(Item); end; initialization Root := TDrawingObject.Create(doBackground); BuildList(Root.DrawingObjectsList); finalization Root.Free; end. FDrawingObjectsList list will handle lifetime of any drawing object added to the list, so you don't have to deal with them. Please note that you cannot add same drawing object to multiple lists as it will be released twice, causing exception. Next, FDrawingObjectsList belongs to its drawing object instance and as such it should be constructed in constructor and destroyed in destructor of TDrawingObject. Nobody else should free that list nor assign anything to its reference there is no reason for it to be writeable property. Constructing/destroying part is the simplest and safest possible, there are other more complex coding patterns that involve lazy initialization, but they require more code and there is more room for bugs. Unless you need to preserve memory as much as possible, you don't need to deal with more complicated code. And if needed you can easily add that later on. There is additional mistake in your destructor declaration. You are missing override directive. Without it destructor will never be called and you will have memory leaks. I have created global Root object and populated it in initialization section. You don't have to make it a global, this is just to illustrate how to work with Root object and how to populate its data. BuildList takes TDrawingObjectsList as a parameter and populates existing list without constructing new one. if the list already has some items it will be cleared - you can omit clearing the list if you know you will populate it only once, or you can clear it in outside code before calling BuildList. I am not going to comment on the interface part as it would be a really long write.
  7. There are some examples here: https://docwiki.embarcadero.com/RADStudio/Sydney/en/Using_an_HTTP_Client var Client: THTTPClient; Response: IHTTPResponse; begin Client := THTTPClient.Create; try Response := Client.Get('https://httpbin.org/get'); ... finally Client.Free; end; This is not just https. Specific example would depend on what kind of request server expects and what kind of response it returns. If the server uses REST architecture there is another set of classes work with REST https://docwiki.embarcadero.com/RADStudio/Sydney/en/Tutorial:_Using_the_REST_Client_Library_to_Access_REST-based_Web_Services
  8. You don't have to use OpenSSL. Delphi has own HTTP classes that support https protocol through OS provided security layer. Unless you have other specific reasons to use Indy, it is easier to use RTL classes (or components) from System.Net namespace than using Indy and fiddling with OpenSSL https://docwiki.embarcadero.com/Libraries/Sydney/en/System.Net
  9. Of course. If the reference and the object is valid longer than the threads using such object, then there is no problem. But there is no need for FreeAndNil then, too. Nor locking. But that only works if that specific point can be moved outside threads or if you can use locking mechanism within threads. I am saying "can use locking" because locking is not always viable solution. You might have situation where such point is not fixed, and shared object instance through multiple interface references may be better choice as the object is valid as long as some thread is using it and you don't need to use locks. Obviously it is developer's fault for using inappropriate code in some scenario. I don't know from where you have pulled "blaming the language" because nobody did that.
  10. Yes, it is a different "program". as automatic memory management requires not only changes in class declarations, but also in how they are used. fixing existing code and making it thread-safe, requires locking mechanism. There are other ways to ensure that the reference is valid while it is being used, but shared counter and atomic increments and decrements are not sufficient to achieve that. I mentioned interfaces, because automatic memory management allows different approach to a problem, and in some scenarios leads to simpler and more maintainable code, that does not require locking mechanisms that blocks other threads. Whether such approach is viable in particular scenario is another question, but we were not talking about exact code and without exact code you can only talk in very broad and general terms. When creating new reference, you don't do that from the background thread, you take existing strong reference and assign it to another one from the context of a thread that holds that strong reference so it cannot become invalid while you are assigning it to another reference. Then you pass that new reference to a new thread. As long as you have strong reference that will not be niled by any other thread, you can safely create new ones from that one. What you cannot do is assigning and nilling the same reference from different threads. No need for any kind of tricks. Another solution for initial problem, would be not calling FreeAndNil from any thread and waiting for all threads to finish before instance is released. But again, without knowing exact code, it is hard to say what is the best and proper solution. I am not sure what you mean with the last sentence.
  11. While we wait for the video, I have written some additional explanation about FreeAndNil thread safety https://dalijap.blogspot.com/2022/07/freeandnil-debate-thread-safety.html
  12. Yes, I know. Situation where we had two different memory models that required slightly different coding patterns was unbearable. When people belittle ARC as memory management model, they tend to miss the fact that the problem with full ARC memory management was not the ARC as memory management model, nor the compiler itself, but the existing code that was not coded according to ARC rules. Hence the whole DisposeOf nightmare we had. Also, every memory management mode has good sides and bad sides. Each model is better for some use cases and worse for other.
  13. DisposeOf is needed solely for compatibility with existing code. Without maintaining compatibility and coding purely according to ARC rules, there would be no need for DisposeOf, too.
  14. I gave my reasons and arguments. I never said anyone has to agree with me. One thing is for sure. With ARC compiler that wouldn't have to care about compatibility with existing codebases there would be no Free nor FreeAndNil.
  15. Fair enough. I am saying that in some situations lifetime is beyond obvious, no matter what you use. Both in locally constructed instances and in instances with larger scope, regardless whether their lifetime is dynamic or not. But I have seen plenty of more complex code, where lifetime is not as clear cut and where there are thousand lines of code involved with multiple references (to different objects that are functionally intertwined). So FreeAndNil in destructor can make a difference between intended behavior and bugs, And the FreeAndNil might solve one bug only to make another one appear. Being able to categorize references based on intended behavior can make untangling such code an easier task. One thing is for sure. For you I don't doubt that you do know what particular code does. I may think that you are needlessly using FreeAndNil, but it will not make me think that your code is possibly bug ridden because you have no idea what you are doing. Unfortunately, that is generally not true and in plenty of code I have seen using FreeAndNil in "wrong" place was nothing comparing to the other coding horrors and bugs it contained.
  16. I am not that smart... I need all the help I can get... I cannot say for sure how would it work for my own code, which I know the best, because I don't use FreeAndNil everywhere. But this has definitely been a problem for me when reading other people's code. Or maybe that is just because it was overall not the best code ever written...
  17. I am talking about scenarios where object instances are lazily constructed or can be nil at some point for other reasons. For instance, think of list of children that is nil if there are no children and is only valid when child is added, but is also destroyed when last child is removed. In such case you would check if the instance is nil and construct the list before adding an new child. If you remove some child and there are no children left in the list, you would then call FreeAndNil on such list. If you are doing some processing on the children, you would just check if the list is nil and skip processing code in such case, because there are no children that need to be processed. So being nil is valid value for such reference and it can become nil at various stages during its owning instance lifetime. This is drastically different coding pattern than having some list which will be constructed in constructor and destroyed in destructor and will be valid reference in the rest of the code. For such references I would use Free and not FreeAndNil. This is the distinction of the code intent I am talking about. If you use FreeAndNil everywhere then you lose the intended design and usage. Of course, tehre are other ways to detect how the instance should be used, but nothing is a problem in simple code and scenarios. In more complex code losing the intent is much harder to deduct and it can mean the whole world of difference. I would say that you can solve that problem with leaving comments in the code, but I have yet to see such comments in code that indiscriminately use FreeAndNil. If I want to detect stale reference access I would use other tools, instead of relying on FreeAndNil. Yes, those are the two scenarios. And for the first one there are better tools, especially since FreeAndNil only nils one reference and you may have other stale ones. Yes, I have occasionally used FreeAndNil for detecting stale pointer access, but only as temporary debugging tool and because I was too lazy to setup FastMM for some reason (read not important project). In other words, I would replace it with Free when the code is fixed (I don't think I have ever used it for debugging purposes more than few times) I am not advocating that anywhere. That is why I am using Free (except for the second scenario with dynamically constructed objects), because I am not touching stale pointers, so using FreeAndNil is pointless.
  18. I was kidding. I don't even have to look at your code to know it is not thread-safe Like I said, using it for debugging purposes when something is off, and for some reason you cannot pinpoint the problem with other tools is fine. Problem is not in using FreeAndNil. It has its use case (beyond debugging purposes). The problem is using it everywhere, and then it obscures the intent of the code. When you FreeAndNil, your code is sending the different message that when you just Free. If you FreeAndNil that means such reference can be nil at any point and all code using such reference also needs to deal with scenario where reference is nil, either constructing new instance if the reference is nil, or skipping operations on nil reference. And that is drastically different code than one dealing with reference that cannot be nil.
  19. One question... you say you are using interfaces and then that calling FreeAndNil pointed you into right direction. Why are you calling Free (or FreeAndNil) on reference counted instance? If reference counting is disabled then the concept of strong and weak references is not applicable.
  20. How much you pay me to prove your Weak library is not thread safe Main problem with FreeAndNil supporters is that it is treated as silver bullet and it is not. Like @Stefan Glienke said, there are better tools for the job. And in multithreading scenario all bets are off. Of course, if you suspect something is out of order then you can add some help like calling FreeAndNil for debugging purposes. Been there, done that. But sprinkling them all over the code, just in case? Sorry, but that is hard no. It just pollutes the code and gives you false sense of security, because it will nil just one reference and all others will turn into dangling pointers. In other words, if FreeandNil can save me 70 hours of work in one case, it would still cost me way more work hours, when I have to read all code with FreeAndNil wondering whether there is a real purpose behind that call or it is there just for luck.
  21. I mean, it can always turn out to be mindless "use this... no use that..." fighting. But without knowing the facts around object construction and destruction process, it is impossible to have an argument based discussion.
  22. There is plenty to talk about. It is not just about FreeAndNil, but about constructing and destructing object and all the fine print around that process. While on the surface this topic seems simple enough and that there is nothing to talk about, it is rather complex topic and many developers, even experienced ones, easily forget about some very important facts around this topic that can cause serious issues in applications.
  23. I have published initial release of NX Horizon Event Bus for Delphi as Open Source on GitHub. Features: implements the publish/subscribe pattern, decoupling publishers and subscribers events are categorized by type any Delphi type can be used as an event supports four types of event delivery: synchronous, asynchronous, synchronous in the context of the main thread, and asynchronous in the context of the main thread provides generic record and reference-counted class wrappers for easier usage and management of existing types as events simple in both implementation and usage fast full thread safety https://github.com/dalijap/nx-horizon
  24. Dalija Prasnikar

    ANN: Open Source Event Bus NX Horizon

    If you are already running it in a thread, then adding event bus on its own will not solve your problem. Even bus would help decoupling your code that is doing the search from the code that is showing the results, but it will not run faster. On the contrary. Since you are adding results to the UI, that part needs to run in the main thread. So you would use TThread.Queue or TThread.Synchronize. Event bus would call the same code in order to run event handler in the main thread. But when you do that you are calling it directly. Sending message through event bus runs a bit more code. You need to create message (event) which will cost some time, depending on the event type and the data it passes. Then sending message alone will lock the collection of subscribers, iterate through that collection, locate appropriate subscriber and then it will invoke event handler for that subscriber. And when iteration is completed it needs to unlock collection. So decoupling comes at some price. In most cases that price is well worth paying, because bus overhead is very small comparing to other code that runs, but it will definitely not run faster than some code that is directly wired and invoked. Why is your code having problems, is hard to say without seeing the code. Also, when you are searching on disk, performance will be tied with the content of the disk, and its hardware characteristics, as well as the whole system. For instance, if you try to access physically damaged part of the disk OS call may hang on such spot for minutes.
  25. Dalija Prasnikar

    ANN: Open Source Event Bus NX Horizon

    Thanks! I will try to add some. I will need some time to prepare some meaningful examples that can show potential use cases. Event bus is a messaging system. Delphi already has basic event bus implementation in System.Messaging https://docwiki.embarcadero.com/CodeExamples/Alexandria/en/System.Messaging_(Delphi) You can also look at the examples there as those use cases apply to my event bus, too. Main difference is that System.Messaging is not thread-safe and you can only use it to send messages in the context of the main thread. If you want to send messages across multiple threads you need a thread-safe event bus, like NX Horizon. Because, it is thread-safe, it also has some additional features like dispatching events (messages) asynchronously in the background thread. Maybe the easies way to explain what is event bus is comparing it to a Button OnClick event handler. When user clicks a button code in the OnClick event handler will run. main difference (besides multithreading support) is that with button and its event handler there is usually deeper connection and there is direct link with the button and its event handler. For instance if you click Help button on some form, you would want to open Help window from its OnClick event handler. But in that case your form with button needs to know about help form. If you have many forms that need to open help form will create tight coupling between all those forms and help form. With event bus, you can declare TOpenHelp event type and then you can subscribe some code to such event type. In your forms with help buttons, you would still need OnClick event handler, but instead of directly opening help form from that OnClick event you can send a message to event bus that TOpenHelp event happened. And then subscribers to that event (there can be more than one) will receive it and run the appropriate code in associated subscription event handler. This way your forms don't need to know about your help form, and code handling your help form does not need to know from where TOpenHelp came from. Event type also serves two purposes. Its type tells that particular event happened, and its content (event can be any automatically managed or value type) is used to pass additional data. for instance if the TOpenHelp is integer type, you use it to store and pass help page number depending on which help button is clicked and then you can open help on particular help page. Another example would be downloading some files in the background thread and then sending TDownloadCompleted event from that thread with some data about particular download and then subscribers can handle and do whatever they need to do with that data. Process it further, show it to the user, or anything else.
×