-
Content Count
1111 -
Joined
-
Last visited
-
Days Won
96
Everything posted by Dalija Prasnikar
-
Using uninitialized object works on Win32, throws AV on Win64
Dalija Prasnikar replied to aehimself's topic in General Help
But, Delphi out parameters have some unpleasantries and many developers choose to use var instead. https://delphisorcery.blogspot.com/2021/04/out-parameters-are-just-bad-var.html -
Using uninitialized object works on Win32, throws AV on Win64
Dalija Prasnikar replied to aehimself's topic in General Help
Yes, you were lucky. Uninitialized variable will contain whatever was previously written at that location. If you were lucky enough that value is zero, broken code would work. Yes, there is a compiler difference one is 32bit compiler another is 64bit one. Pointer sizes are different. Memory layout will be different. But, different compiler is besides the point. Working with uninitialized variables is undefined behavior. That means anything can happen even with the same compiler. -
A better way to share global data structures than as global variables?
Dalija Prasnikar replied to DavidJr.'s topic in Algorithms, Data Structures and Class Design
TMessage from System.Messaging? System.Messaging is not thread-safe so you cannot use it for anything thread related. -
Class properties: Wins prettyness over functionality ?
Dalija Prasnikar replied to Rollo62's topic in Algorithms, Data Structures and Class Design
Different languages have different set of features and also differ in implementations of those features. Properties in general are a tool that provides additional level of abstraction around encapsulation and enables future implementation changes while preserving stable public API. Some of the benefits are more visible in some languages than the others. For instance, if you have public field Name and you want to add some code around retrieving that field is easy to do in Delphi. You can rename field and move it to private section and declare public function Name to retrieve it. I Java, you cannot do such thing because calling method must include brackets. This requires refactoring all code that uses such field. If you want to add setter, you will break the code in any language. This is where using properties helps with encapsulation. They hide unnecessary implementation details and give implementing class to ability to change those without breaking user code. You can start with simple field backed property, which from performance aspect is no different than public field and you can add getters and setters as needed without breaking code. Without properties, you can also maintain stable API, but the cost is having getters and setters for everything and paying the price in performance. No matter how small it is, eventually it can add up. Additionally, code with simple assignment is easier to read than setter method. There are some parts of general properties functionality that Delphi does not implement, like different access levels for reading and writing, or some additional ceremony when declaring properties, especially in interfaces. Some of those could be improved to make properties more flexible, but lacking them is poor argument against using properties. In situations where you really need some functionality properties don't provide, you can use other ways to achieve what you need, but not using properties everywhere else because you cannot do something in rare occasions is also not very convincing argument. Arguments around name refactoring are not very convincing either. They compare name refactoring, where there is a bit more renaming in declaration. Now, compare that single place where you need to make additional rename, to refactoring all code in case where you need to replace public fields with accessor methods. When it comes to extra declaration code needed for properties with accessor methods comparing to only having accessor methods, think how much unnecessary getters and setter methods you need to write in cases where you could use field backed property declaration. Overall using properties results with cleaner code and having more functionality than you can have with simple fields or just accessor methods. The little bit of ceremony around the declaration is price I am more than willing to pay, to get all other benefits. -
Class methods Polyformism
Dalija Prasnikar replied to Sam Witse's topic in Algorithms, Data Structures and Class Design
You cannot use property. The only thing you can do is removing property and static getter and renaming virtual getter function to id.- 8 replies
-
- class method
- polyformism
-
(and 1 more)
Tagged with:
-
Class methods Polyformism
Dalija Prasnikar replied to Sam Witse's topic in Algorithms, Data Structures and Class Design
procedure TForm2.Button1Click(Sender: TObject); begin Edit1.Text := inttostr(TChild.id) { <= Calling the Child's property} end; When you use the above call, TChild.id calls static GetMasterID method. Because that method is static it does not have Self parameter passed, which in context of class methods represents class itself. So when you are inside GetMasterID method, compiler no longer knows from which class you have called that method. It only knows the class where the method is implemented, in this case TMaster. And calling GetChildID will be interpreted as calling TMaster.GetChildID. If you remove abstract on TMaster.GetChildID and implement that function as regular virtual method, which returns different integer than TChild.GetChildID you will no longer have abstract exception, but you will get wrong results.- 8 replies
-
- class method
- polyformism
-
(and 1 more)
Tagged with:
-
Which option to use for a large batch of REST queries?
Dalija Prasnikar replied to David Schwartz's topic in OmniThreadLibrary
Testing is one things, calling something that serves no purpose is another. If the system is over stressed then pumping messages from UpdateLV will not make it run any faster. If the system is not stressed it will pump messages even without you forcing it, literally as soon as you exit UpdateLV method. If you have too many items on list view and UpdateLV is killing your overal performance, then you should modify that logic and instead of updating the whole list all the time update only item that is modified. Yes, you could see some differences in behavior with Application.ProcessMessages, but none that really matter. Just remove those. -
Which option to use for a large batch of REST queries?
Dalija Prasnikar replied to David Schwartz's topic in OmniThreadLibrary
Why? It serves no purpose whatsoever. I am not familiar with OTL enough to comment other code. -
Manager, I am using datasnap on fmx mobile. How can I handle it on mobile using TTask.Run(..)? Thanks in advance for your help.
Dalija Prasnikar replied to TELOS KIM's topic in FMX
Can you please translate your logic to English. It is extremely hard to follow what you are doing. Especially, since TTask.Run code is basically empty and it requires way more context. -
Understandable. I would do the same. GPX format is ideal for SAX parser. Avoiding allocations of thousands of XML nodes would be my best bet for optimization.
-
Unrelated to the profiling, there are other optimizations. First, SAX parsing is generally more performant than DOM parsing, especially when DOM is based on interfaces. If you don't need XML DOM, then building your business classes directly during parsing will be more efficient. But not all structures cane be equally easy parsed by SAX. Next, IXmlDoc works on top of standard IDOM interfaces, so you have additional slowdown there. If you cannot use SAX, modifying code to work directly with IDOM interfaces might be a solution. Or using different DOM parser.
-
Sampling profiler will give you better insight. https://www.delphitools.info/samplingprofiler/
-
Interface question
Dalija Prasnikar replied to David Schwartz's topic in Algorithms, Data Structures and Class Design
I cannot say whether something in logs changed, but as far as I can remember FastMM works in Sidney the same way it worked before. I don't have the Tokyo installed for comparison. And it shows the stack trace correctly so I can follow to the line where issue happened. Yes, I know that in more complex code it can be harder to figure out real culprit, but that has always been the case. -
Interface question
Dalija Prasnikar replied to David Schwartz's topic in Algorithms, Data Structures and Class Design
Would you elaborate that? Memory manager works fine in Sydney and detects memory leaks. -
BestPractices: To raise, or not to raise ... an Exception in a class constructor
Dalija Prasnikar replied to Rollo62's topic in Algorithms, Data Structures and Class Design
I am talking about your comment to @Wagner Landgraf where he mentioned memory management and you are saying this thread is not about memory management. I am not trying to prove anything, just wanted to say that memory management is indirectly involved in this conversation, and Wagner didn't post in the wrong thread. -
BestPractices: To raise, or not to raise ... an Exception in a class constructor
Dalija Prasnikar replied to Rollo62's topic in Algorithms, Data Structures and Class Design
The way I am reading that is: if you pass parameters in constructor to initialize fields and you validate them there, raising exception if they are not valid, then you can avoid checking those fields when you are using them in other places because you know they cannot hold invalid values. -
BestPractices: To raise, or not to raise ... an Exception in a class constructor
Dalija Prasnikar replied to Rollo62's topic in Algorithms, Data Structures and Class Design
try...finally implies cleanup which in Delphi terms implies memory management Maybe memory management is not main topic, but it is certainly related. -
BestPractices: To raise, or not to raise ... an Exception in a class constructor
Dalija Prasnikar replied to Rollo62's topic in Algorithms, Data Structures and Class Design
Depends on the context. If you open some file for processing and it turns out to be a too large so processing it raises out of memory, you just clean up and tell to the user: "Sorry, your file is too large and you don't have enough memory." But after proper cleanup your application will be in fine condition to process some other smaller file. On the other hand, there are situations where out of memory is not recoverable. You still may be able to show message to the user there is not enough memory, but you will just have to kill the application after that. -
BestPractices: To raise, or not to raise ... an Exception in a class constructor
Dalija Prasnikar replied to Rollo62's topic in Algorithms, Data Structures and Class Design
What do you mean by plan B? -
BestPractices: To raise, or not to raise ... an Exception in a class constructor
Dalija Prasnikar replied to Rollo62's topic in Algorithms, Data Structures and Class Design
If you want to handle the exception on site, then the second option is the wrong way to do it for several reasons. Construction of an object can always fail because of OutOfMemory, so if you wanted to handle all exceptions at that point you have failed to do so. If you are fine to bubble up that exception further on and if except part (handling the exception) cannot raise exceptions, you don't need try..finally at all. -
BestPractices: To raise, or not to raise ... an Exception in a class constructor
Dalija Prasnikar replied to Rollo62's topic in Algorithms, Data Structures and Class Design
You tell me. It doesn't feel bad to me at all I think you are overcomplicating. If you have class that requires some setup (that will commonly not be changed once object is created) to function properly then passing those parameters through constructor and raising exception in constructor is the best and simplest thing to do. Use the approach that requires the least amount of code for safely using such class and where you cannot easily forget to do something vital. Usually that will be the best code. -
BestPractices: To raise, or not to raise ... an Exception in a class constructor
Dalija Prasnikar replied to Rollo62's topic in Algorithms, Data Structures and Class Design
Actual purpose of try...finally in above code is to ensure cleanup of the MyThing instance if MyThing.DoIt raises exception. If constructor raises the exception there will be automatic cleanup and MyThing.Free will never be, nor it should be called. -
BestPractices: To raise, or not to raise ... an Exception in a class constructor
Dalija Prasnikar replied to Rollo62's topic in Algorithms, Data Structures and Class Design
No, you don't. If the instance is never constructed it will be nil in the destructor and you can just call Free on such instance. You only need to consider that any instance in the destructor can be nil, so if you are calling any other methods you need to check for nil before calling those in destructor. -
BestPractices: To raise, or not to raise ... an Exception in a class constructor
Dalija Prasnikar replied to Rollo62's topic in Algorithms, Data Structures and Class Design
Nobody said that you must validate in the constructor. It all depends whether this is critical or not and at which point. There are no wrong or right answers here, it all depends how class functionality and how it is used. Each approach has downsides and upsides. -
BestPractices: To raise, or not to raise ... an Exception in a class constructor
Dalija Prasnikar replied to Rollo62's topic in Algorithms, Data Structures and Class Design
Yes. All fields are zero initialized. There is no double safety if something cannot ever happen. If you have extra initialization code then such unnecessary code can obscure other important code. Keep it simple. If you are not sure what is initialized and when, it is better to check and learn than to use code just in case. It is fine to construct as many instances as you need and protect them with single try...finally. You don't need to pay attention to the order of destruction, unless there is some special reason where one instance still holds reference to other one you are destroying sooner, where you might have problem with dangling pointers. There is no functional difference, only one nil assignment more in your case - if you feel like you can more easily follow the code if multiple instances are all initialized before try..finally, that is fine. Remember, try...finally is used just for cleanup in case of exception, not for handling the exception. If exception is raised inside try..finally it will be propagated to the next exception handler block - try...except just the same it would if it is raised outside try..finally. Again, if there is exception raised in constructor, assignment to the variable will never happen. So if LA is nil and the you call LA := TRaiseOnMinus.Create(-2) in finally block LA will still be nil. Automatic cleanup for that unassigned object instance is happening in hidden code inserted by compiler. If the instance is successfully created, then automatic cleanup will not happen. Raising exceptions in constructor is not evil nor bad practice. It is perfectly fine thing to do. Whether you will raise exception in constructor or not, is matter of each particular class functionality. If you pass invalid parameter to a constructor it makes sense that such constructor raises exception, because otherwise your object is not properly functional instance, If you don't raise exception then, you would have to sprinkle your code all over inside that class and where you use it with checks for that particular invalid condition. When you have some condition that causes failure failing soon is always better than failing later on. If you have some reasons not to raise exception or there is nothing special that would require raising exception that is also fine. Constructing objects can always raise OutOfMemory so you always need to be prepared to do the cleanup anyway. Take for instance TFileStream - if constructor fails to open or create file it will raise an exception. And you can handle that failure at that point. If you don't have to handle it at that point, that means you have opened file too soon.