-
Content Count
2848 -
Joined
-
Last visited
-
Days Won
155
Everything posted by Anders Melander
-
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. -
ANN: Better Translation Manager released
Anders Melander replied to Anders Melander's topic in Delphi Third-Party
But how? -
ANN: Better Translation Manager released
Anders Melander replied to Anders Melander's topic in Delphi Third-Party
It's been a while but I thought all your customers were using remote desktop against servers hosted and managed centrally by you. Regardless, I guess a self-extracting exe could be used. For example a simple zip self-extractor or even an Inno Setup installer with no GUI. However if your problem is file locking (presumably because the files are in use), I can't see that you won't still have the same problem; If the files are locked the extraction will not be able to replace them. I think it would be better to concentrate on solving the deployment problem instead of working around it. -
DevExpress Spreadsheet - Option to suppress exception message The cell that you are trying to change is protected and therefore read-only.
Anders Melander replied to Fons N's topic in Delphi Third-Party
The DevExpress support groups would be a good place to search for/ask this question. https://supportcenter.devexpress.com/ticket/details/t545652/error-editing-protected-spreadsheet https://supportcenter.devexpress.com/ticket/details/t745921/what-is-the-best-way-for-have-a-spreadsheet-in-readonly-mode FWIW, I think the response given by DevExpress is BS; IMO using an exception to display a message to the end user is an extremely poor solution. This behavior should at least be optional - But good luck getting them to change it. -
How to 'disconnect' a TFDQuery keeping the datas.
Anders Melander replied to PhilPlus's topic in Databases
Read the documentation. Search for FireDAC offline