-
Content Count
2771 -
Joined
-
Last visited
-
Days Won
147
Everything posted by Anders Melander
-
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 -
What would be the best way to draw a Dial that rotates up to 360 degrees with indicator?
Anders Melander replied to Al T's topic in VCL
It completely depends on how you want it to look. Show us a mockup of how you imagined it should look and then we can help you. -
ANN: Better Translation Manager released
Anders Melander replied to Anders Melander's topic in Delphi Third-Party
Potential chicken-egg problem: The translation is based on the exe file. The language module is based on the translation + exe. In order to get the language module linked into the resources of the exe, the exe must be compiled with it. Of course this isn't impossible in any way, and you can even make a tool that adds the file to the exe's existing resources, but then there's the next problem: The resource modules must be extracted from the exe before the exe loads the resource module, which by default happens in the initialization section of system or sysutils, I forget which. All in all, I'd say it's probably easier and more robust to solve the original problem instead of all these workarounds.