-
Content Count
2829 -
Joined
-
Last visited
-
Days Won
154
Everything posted by Anders Melander
-
Forget about that. It will never work in a multi-user environment. You cannot "check for locks" without acquiring a lock. See race condition. Yes, there is. All statements are executed in a transaction. Your DevArt connection settings are probably set to use implicit auto transaction so this is hidden from you but I'm positive that you can configure it so transactions must be made explicitly. It's actually not that hard once you understand the different transaction isolation levels. I suggest you start there: https://mariadb.com/kb/en/mariadb-transactions-and-isolation-levels-for-sql-server-users/
-
This whole thread is a big waste of everyone's time, including the OP. There's no point in trying to come up with alternate solutions when it seems no real attempt has been made to locate and isolate the cause of the problem. Run your application in the debugger. When the out-of-memory occurs, look at the call stack and place a breakpoint somewhere up the call stack before the call to the lower level method. Reset the debug session and run again. When the breakpoint is hit, single-step into the methods below, watch the memory consumption and try to understand what's going on in the code. At some point, you will likely arrive at the location where too much memory is allocated and the cause and/or solution will present itself. I do have a hunch about what the problem is, but it's no better than all the other guesses when the basic troubleshooting hasn't been done.
-
How is that different from the way the standard Delphi RTL translation system works? Resourcestring and form translations are stored in external language modules, one per language, and at run-time forms and strings are loaded either from the exe or from a language module depending on the desired language.
-
Sweet 16: Delphi/Object Pascal
Anders Melander replied to DJof SD's topic in Tips / Blogs / Tutorials / Videos
I see. Well, assembler is used with many different languages: Delphi, C, C++, etc, so that sounds perfectly reasonable to me. I would actually expect it to have a higher ranking than twice that of Delphi. FWIW, I just tried searching github for "eax" in the Pascal, C and C++ file types: pas: 41,053 files, inc: 61,659 files c: 5,930,801 files, h: 3,686,546 files cpp: 499,900 files, hpp: 74,991 files According to the search, there are a total of 2,245,735 pas files on Github, so 1.8% of the Pascal files (.pas) contain assembler. There are 1,098,004,054 c files, so 0.5% of those contain assembler. If the file count is representative of the TIOBE ranking (it's not), then the above suggests that assembler is approximately 5 times more used than Pascal. All these stats are of course completely bogus because the numbers don't take file/repo duplicates, abandoned, or archived content into account. -
Sweet 16: Delphi/Object Pascal
Anders Melander replied to DJof SD's topic in Tips / Blogs / Tutorials / Videos
People who write low-level code where performance is important. If by "widely used" you mean "used by most" then no. But then it never was. "Most people" wouldn't know how to create the tools or write the libraries that they use, but someone has to do it. Even if you don't have a need to write assembler, knowledge of it makes you a better developer because it gives you a deeper understanding of what's going on and why. The same goes for hardware. -
Instead of all this guesswork why not simply use the debugger to determine where the out-of-memory occurs?
-
System.Generics.Collections.TList.BinarySearch if there are duplicates
Anders Melander replied to dummzeuch's topic in RTL and Delphi Object Pascal
And where is this written? Whoever made the change obviously did it to handle lists with duplicates, so it's pointless to argue that lists are usually without duplicates. It's fine that there are corner cases that performs worse than optimal, like with quick sort, but the worst case here is a bit extreme considering that it could have been avoided with a bit of effort - or they could have just Googled the solution. There's just no excuse for the current implementation. -
Once again I'm struggling with the fact that the compilers Return Value Optimization of interfaces produces code that keeps interfaces alive beyond the scope of the block in which they are referenced. For example let's say that I have a function CreateFoo that creates a reference counted object and returns an interface to this object: begin var Foo := CreateFoo; ... Foo := nil; ... end; One would think it was reasonable to assume that, given no other references to the object besides the Foo variable, once I nill the Foo reference then the reference count goes to zero and the object is destroyed. Right?... Nope. It seems that what the compiler actually produces is something like this: var Gotcha: IUnknown; begin Gotcha := nil; try begin Gotcha := CreateFoo; var Foo := Gotcha as IUnknown; ... Foo := nil; ... end; finally Cotcha := nil; end; end; Since this is an old, known problem I wonder if anyone has been able to come up with a work around. I have mostly been able to work around it in my own code by simply not relying on reference counted objects being destroyed inside local blocks but I have a few places where I simply either have to make this work properly or abandon reference counting. FWIW, the following reproduces the problem: program FooFail; {$APPTYPE CONSOLE} {$R *.res} uses Classes; type TFoo = class(TInterfacedObject) public constructor Create; destructor Destroy; override; end; constructor TFoo.Create; begin inherited Create; WriteLn(' Create'); end; destructor TFoo.Destroy; begin WriteLn(' Destroy'); inherited; end; function CreateFoo: IUnknown; begin Result := TFoo.Create; end; begin WriteLn('Begin'); begin var Foo1: IUnknown := TFoo.Create; Foo1 := nil; // Foo1 destroyed here end; begin var Foo2: IUnknown := CreateFoo; Foo2 := nil; end; WriteLn('End'); end. // Foo2 destroyed here The expected desired output is: Begin Create Destroy Create Destroy End The actual output is: Begin Create Destroy Create End Destroy
-
Searching for full-time remote position...
Anders Melander replied to Rick_Delphi's topic in Job Opportunities / Coder for Hire
P.S. Good luck with the writing -
Actually, I didn't - until now. Same problem, I'm afraid. I haven't QP'd it and will probably not have time to do so anytime soon; We've just updated our main product suite to Delphi 11.2 (from 10.3) and there's plenty of other stuff that needs my attention. Here's the original test case updated to exhibit the observed behavior: program FooFailMore; {$APPTYPE CONSOLE} {$R *.res} uses Classes; type IFoo = interface ['{28036C58-4E0E-422C-AAE1-7DDEFF51C75D}'] procedure DoFoo; end; TFoo = class(TInterfacedObject, IFoo) private procedure DoFoo; public constructor Create; destructor Destroy; override; end; constructor TFoo.Create; begin inherited Create; WriteLn('Create'); end; destructor TFoo.Destroy; begin WriteLn('Destroy'); inherited; end; procedure TFoo.DoFoo; begin WriteLn('Foo'); end; function CreateFoo: IUnknown; begin Result := TFoo.Create; end; procedure Test; begin WriteLn('Begin'); begin var Foo1 := TFoo.Create as IFoo; Foo1.DoFoo; Foo1 := nil; // Foo1 destroyed here end; begin var Foo2 := CreateFoo as IFoo; Foo2.DoFoo; Foo2 := nil; end; WriteLn('End'); end; // Foo2 destroyed here begin Test; ReadLn; end. Expected output: Actual output:
-
System.Generics.Collections.TList.BinarySearch if there are duplicates
Anders Melander replied to dummzeuch's topic in RTL and Delphi Object Pascal
Wikipedia (even though it references the almighty Knuth) isn't the definition". It's a definition. -
Yes, probably. There are plenty of workarounds but that wasn't really the point.
-
System.Generics.Collections.TList.BinarySearch if there are duplicates
Anders Melander replied to dummzeuch's topic in RTL and Delphi Object Pascal
The famous Quick Fix™ technique - Sponsored by Intel and your local power company. -
For Delphi, Code Coverage Report with sonarqube
Anders Melander replied to hakki.degirmenci's topic in Software Testing and Quality Assurance
Please read the documentation. I have never used or even heard of sonarqube but it took me less than 2 minutes to find the information: https://docs.sonarqube.org/latest/analyzing-source-code/test-coverage/overview/ https://docs.sonarqube.org/latest/analyzing-source-code/test-coverage/generic-test-data/ -
Not if FunctionReturningInterface returns an IBar interface or anything other than IFoo. The actual code is an object factory where I pass an interface ID (i.e. a GUID) to a method and get an instance that implements that interface back. Something like this: var MyDialog := DialogManager.CreateDialog(IMyDialog) as IMyDialog; // CreateDialog returns an IInterface MyDialog.Execute; DialogManager itself is also an interface so I can't use generics on it. If it had been an object then I could have done like this instead: var MyDialog := DialogManager.CreateDialog<IMyDialog>; // CreateDialog returns an IMyDialog MyDialog.Execute;
-
For Delphi, Code Coverage Report with sonarqube
Anders Melander replied to hakki.degirmenci's topic in Software Testing and Quality Assurance
Delphi doesn't appear to be supported by sonarqube: https://docs.sonarqube.org/latest/analyzing-source-code/languages/overview/ ...and as far as I can tell sonarqube doesn't generate the coverage data itself but relies on coverage data supplied by other tools. -
Not quite fixed it seems 😞 Casting a function result with the interface as operator and the old behavior is back. Reproduced with Delphi 11.2. This works: begin var Foo := FunctionReturningInterface; // RefCount = 1 Foo := nil; // RefCount = 0 ... end; but this doesn't: begin var Foo := FunctionReturningInterface as IFoo; // RefCount = 2 Foo := nil; // RefCount = 1 ... end; // RefCount = 0 Workaround: begin var Foo: IFoo; begin var := TempFoo := FunctionReturningInterface; // RefCount = 1 Foo := TempFoo as IFoo; // RefCount = 2 end; // RefCount = 1 Foo := nil; // RefCount = 0 ... end; or function FooFunc: IFoo; begin Result := FunctionReturningInterface as IFoo; // RefCount = 2 end; // RefCount = 1 begin var Foo := FooFunc; // RefCount = 1 Foo := nil; // RefCount = 0 ... end;
-
Well, it's just pseudo code that happens to look a lot like Delphi code 🙂 . In my defense, I think it actually works as I intended; It will return a match within the tolerance but it might not return the closest match.
-
You're right. I tried to come up with a trivial example - and failed. Anyway, you get the point.
-
So how would you compare floats with tolerance? function BinarySearch(const List: TArray<Double>; Value: Double; Tolerance: Double): integer; begin var Lo := 0; var Hi := High(List); while (Lo ≤ Hi) do begin var Mid := (Lo + Hi) div 2; if SameValue(List[Mid], Value, Tolerance) then exit(Mid); if List[Mid] < Value then Lo := Mid+1 else Hi := Mid-1; end; Result := -1; end;
-
Okay, so there's basically nothing wrong with the functions. Thanks.
-
Why? What's wrong with them?
-
How is that relevant?
-
ANN: Better Translation Manager released
Anders Melander replied to Anders Melander's topic in Delphi Third-Party
I can't see why it's "better", it's certainly more complicated, but yes that's also an alternative. AFAIR resources are mapped into the process virtual address space so that will have to be taken into consideration. I'm not sure you can sign an exe that has had data appended and even if you can you risk that the signature data is added after the data you appended thus breaking the extraction scheme. -
ANN: Better Translation Manager released
Anders Melander replied to Anders Melander's topic in Delphi Third-Party
Okay then, assuming your exe isn't signed you can try this: At build time (after the exe and language modules have been built): Zip your language modules into a single file. Append the zip to the end of the exe file. Append a int64 containing the original size of the zip to the end of the exe file. You will need to make a tool that does the above. It shouldn't be too hard. At run time: Open a TFileStream on the exe and read the int64 from the end of the exe. This gives you the position of the zip inside the exe. Seek the stream to the position of the zip. Open a TZipFile on the stream and extract the files to disk. If your exe is signed you will need to use a different approach. See https://blog.barthe.ph/2009/02/22/change-signed-executable/ See also: https://stackoverflow.com/questions/5795446/appending-data-to-an-exe